Skip to content

Commit

Permalink
Add dynamic phase gradient gates and phaser tests
Browse files Browse the repository at this point in the history
- Implemented DynamicPhaseGradientFamily gates and added them to toolbox
- Renamed 'Fourier' toolbox section to 'Frequency'
- Tweaked phase gradient tooltips
- Changed phase gradient symbol to "Grad^x"
- Added assertThatGateActsLikePhaser test util
- Added forcedTime parameter to assertThatCircuitMutationActsLikeMatrix
- Added gatesActLikeTheirKnownPhasingFunction global test
  • Loading branch information
Strilanc committed Aug 15, 2017
1 parent 4cc4363 commit ce13cad
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 22 deletions.
8 changes: 5 additions & 3 deletions src/gates/AllGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,15 @@ Gates.BottomToolboxGroups = [
]
},
{
hint: 'Fourier',
hint: 'Frequency',
gates: [
FourierTransformGates.FourierTransformFamily.ofSize(2),
FourierTransformGates.InverseFourierTransformFamily.ofSize(2),
undefined, undefined,
PhaseGradientGates.PhaseGradientFamily.ofSize(2), PhaseGradientGates.PhaseDegradientFamily.ofSize(2),
undefined, undefined,
PhaseGradientGates.PhaseGradientFamily.ofSize(2),
PhaseGradientGates.PhaseDegradientFamily.ofSize(2),
PhaseGradientGates.DynamicPhaseGradientFamily.ofSize(2),
PhaseGradientGates.DynamicPhaseDegradientFamily.ofSize(2),
]
},
{
Expand Down
38 changes: 31 additions & 7 deletions src/gates/PhaseGradientGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
// limitations under the License.

import {Gate} from "src/circuit/Gate.js"
import {GatePainting} from "src/draw/GatePainting.js"
import {ketArgs, ketShaderPhase} from "src/circuit/KetShaderUtil.js"
import {WglArg} from "src/webgl/WglArg.js"
import {WglConfiguredShader} from "src/webgl/WglConfiguredShader.js"

const PHASE_GRADIENT_SHADER = ketShaderPhase(
'uniform float factor;',
Expand All @@ -28,27 +28,51 @@ let PhaseGradientGates = {};

PhaseGradientGates.PhaseGradientFamily = Gate.buildFamily(1, 16, (span, builder) => builder.
setSerializedId("PhaseGradient" + span).
setSymbol("e^iπ%").
setTitle("Phase Gradient Gate").
setBlurb("Phases by an amount proportional to the target value.").
setSymbol("Grad^½").
setTitle("Half Gradient Gate").
setBlurb("Phases the target by an amount proportional its value.").
setActualEffectToShaderProvider(ctx => PHASE_GRADIENT_SHADER.withArgs(
...ketArgs(ctx, span),
WglArg.float("factor", Math.PI / (1 << span)))).
setKnownEffectToPhaser(k => k / (2 << span)));

PhaseGradientGates.PhaseDegradientFamily = Gate.buildFamily(1, 16, (span, builder) => builder.
setSerializedId("PhaseUngradient" + span).
setSymbol("e^-iπ%").
setTitle("Inverse Phase Gradient Gate").
setBlurb("Counter-phases by an amount proportional to the target value.").
setSymbol("Grad^-½").
setTitle("Inverse Half Gradient Gate").
setBlurb("Counter-phases the target by an amount proportional its value.").
setActualEffectToShaderProvider(ctx => PHASE_GRADIENT_SHADER.withArgs(
...ketArgs(ctx, span),
WglArg.float("factor", -Math.PI / (1 << span)))).
setKnownEffectToPhaser(k => -k / (2 << span)));

PhaseGradientGates.DynamicPhaseGradientFamily = Gate.buildFamily(1, 16, (span, builder) => builder.
setSerializedId("grad^t" + span).
setSymbol("Grad^t").
setTitle("Cycling Gradient Gate").
setBlurb("Phases the target by a cycling amount proportional its value.").
setActualEffectToShaderProvider(ctx => PHASE_GRADIENT_SHADER.withArgs(
...ketArgs(ctx, span),
WglArg.float("factor", ctx.time * Math.PI * 2))).
promiseEffectOnlyPhases().
setDrawer(GatePainting.makeCycleDrawer(-1, -1)));

PhaseGradientGates.DynamicPhaseDegradientFamily = Gate.buildFamily(1, 16, (span, builder) => builder.
setSerializedId("grad^-t" + span).
setSymbol("Grad^-t").
setTitle("Inverse Cycling Gradient Gate").
setBlurb("Counter-phases the target by a cycling amount proportional its value.").
setActualEffectToShaderProvider(ctx => PHASE_GRADIENT_SHADER.withArgs(
...ketArgs(ctx, span),
WglArg.float("factor", -ctx.time * Math.PI * 2))).
promiseEffectOnlyPhases().
setDrawer(GatePainting.makeCycleDrawer(1, -1)));

PhaseGradientGates.all = [
...PhaseGradientGates.PhaseGradientFamily.all,
...PhaseGradientGates.PhaseDegradientFamily.all,
...PhaseGradientGates.DynamicPhaseGradientFamily.all,
...PhaseGradientGates.DynamicPhaseDegradientFamily.all,
];

export {PhaseGradientGates, PHASE_GRADIENT_SHADER}
4 changes: 2 additions & 2 deletions src/math/Complex.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ class Complex {

/**
* Returns a complex number with the given magnitude and phase.
* @param {!number} magnitude
* @param {!number} phase
* @param {!number} magnitude Distance from origin.
* @param {!number} phase Phase in radians.
* @returns {!Complex}
*/
static polar(magnitude, phase) {
Expand Down
31 changes: 26 additions & 5 deletions test/CircuitOperationTestUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,39 @@ function assertThatGateActsLikePermutation(
});
}

/**
* @param {!Gate} gate
* @param {!function(target : !int) : !number} phaserFunc
* @param {!number|undefined=} forcedTime
*/
function assertThatGateActsLikePhaser(gate, phaserFunc, forcedTime=undefined) {
let wireCount = gate.height;
let col = new Array(wireCount).fill(undefined);
col[0] = gate;
let circuit = new CircuitDefinition(wireCount, [new GateColumn(col)]);
let matrix = Matrix.generateDiagonal(1 << wireCount, k => Complex.polar(1, phaserFunc(k)*Math.PI*2));
let updateAction = ctx => advanceStateWithCircuit(ctx, circuit, false);
assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix, forcedTime);
}

/**
* @param {function(!CircuitEvalContext)} updateAction
* @param {!Matrix} matrix
* @param {!int=} repeats
* @param {!number|undefined=} forcedTime
*/
function assertThatCircuitUpdateActsLikeMatrix(updateAction, matrix, repeats=5) {
function assertThatCircuitUpdateActsLikeMatrix(updateAction, matrix, repeats=5, forcedTime=undefined) {
for (let i = 0; i < repeats; i++) {
assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix);
assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix, forcedTime);
}
}

/**
* @param {function(!CircuitEvalContext) : void} updateAction
* @param {function(!CircuitEvalContext)} updateAction
* @param {!Matrix} matrix
* @param {!number|undefined=} forcedTime
*/
function assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix) {
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();
Expand All @@ -166,6 +183,9 @@ function assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix) {
time = 0;
qubitIndex = 0;
}
if (forcedTime !== undefined) {
time = forcedTime;
}
let wireCount = qubitSpan + extraWires;
let controls = Controls.NONE;
for (let i = 0; i < extraWires; i++) {
Expand Down Expand Up @@ -217,7 +237,7 @@ function assertThatCircuitShaderActsLikePermutation(wireCount, shaderMaker, perm

/**
* @param {!int} wireCount The number of wires in the circuit.
* @param {!function(!CircuitEvalContext) : void} updateAction The actual update action.
* @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.
*/
Expand Down Expand Up @@ -267,4 +287,5 @@ export {
assertThatCircuitOutputsBasisKet,
assertThatCircuitUpdateActsLikePermutation,
assertThatCircuitShaderActsLikePermutation,
assertThatGateActsLikePhaser,
}
2 changes: 2 additions & 0 deletions test/circuit/Serializer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ const IDS_THAT_SHOULD_BE_KNOWN = [
"rev2", "rev3", "rev4", "rev5", "rev6", "rev7", "rev8", "rev9", "rev10", "rev11", "rev12", "rev13", "rev14", "rev15", "rev16",
"weave4", "weave5", "weave6", "weave7", "weave8", "weave9", "weave10", "weave11", "weave12", "weave13", "weave14", "weave15", "weave16",
"split4", "split5", "split6", "split7", "split8", "split9", "split10", "split11", "split12", "split13", "split14", "split15", "split16",
"grad^t1", "grad^t2", "grad^t3", "grad^t4", "grad^t5", "grad^t6", "grad^t7", "grad^t8", "grad^t9", "grad^t10", "grad^t11", "grad^t12", "grad^t13", "grad^t14", "grad^t15", "grad^t16",
"grad^-t1", "grad^-t2", "grad^-t3", "grad^-t4", "grad^-t5", "grad^-t6", "grad^-t7", "grad^-t8", "grad^-t9", "grad^-t10", "grad^-t11", "grad^-t12", "grad^-t13", "grad^-t14", "grad^-t15", "grad^-t16",
];

suite.test("known_gates_backwards_compatible", () => {
Expand Down
19 changes: 16 additions & 3 deletions test/gates/AllGates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import {Gate} from "src/circuit/Gate.js"
import {seq} from "src/base/Seq.js"
import {WglTextureTrader} from "src/webgl/WglTextureTrader.js"
import {currentShaderCoder} from "src/webgl/ShaderCoders.js"
import {assertThatGateActsLikePermutation} from "test/CircuitOperationTestUtil.js"
import {
assertThatGateActsLikePermutation,
assertThatGateActsLikePhaser
} from "test/CircuitOperationTestUtil.js"

let suite = new Suite("AllGates");

Expand Down Expand Up @@ -137,6 +140,14 @@ suite.testUsingWebGL("gatesActLikeTheirKnownPermutation", () => {
}
});

suite.testUsingWebGL("gatesActLikeTheirKnownPhasingFunction", () => {
for (let gate of Gates.KnownToSerializer) {
if (gate.knownPhaseTurnsFunc !== undefined && gate.height <= 3) {
assertThatGateActsLikePhaser(gate, gate.knownPhaseTurnsFunc);
}
}
});

suite.testUsingWebGL("knownNonUnitaryGates", () => {
let nonUnitaryGates = new Set(Gates.KnownToSerializer.
filter(g => !g.isDefinitelyUnitary()).
Expand Down Expand Up @@ -184,7 +195,7 @@ suite.test("knownDoNothingGateFamilies", () => {
]));
});

suite.testUsingWebGL("knownDynamicGateFamilies", () => {
suite.test("knownDynamicGateFamilies", () => {
let dynamicFamilies = new Set(Gates.KnownToSerializer.
filter(g => g.stableDuration() !== Infinity).
map(g => g.gateFamily[0].serializedId));
Expand All @@ -210,6 +221,8 @@ suite.testUsingWebGL("knownDynamicGateFamilies", () => {
'>>t2',
'<<t2',
'X^⌈t⌉',
'X^⌈t-¼⌉'
'X^⌈t-¼⌉',
'grad^t1',
'grad^-t1',
]));
});
19 changes: 17 additions & 2 deletions test/gates/PhaseGradientGates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
// limitations under the License.

import {Suite} from "test/TestUtil.js"
import {assertThatCircuitShaderActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {PHASE_GRADIENT_SHADER} from "src/gates/PhaseGradientGates.js"
import {
assertThatCircuitShaderActsLikeMatrix,
assertThatGateActsLikePhaser,
} from "test/CircuitOperationTestUtil.js"
import {PHASE_GRADIENT_SHADER, PhaseGradientGates} from "src/gates/PhaseGradientGates.js"

import {Complex} from "src/math/Complex.js"
import {Matrix} from "src/math/Matrix.js"
Expand All @@ -32,3 +35,15 @@ suite.testUsingWebGL('PHASE_GRADIENT_SHADER', () => {
ctx => PHASE_GRADIENT_SHADER.withArgs(...ketArgs(ctx, 4), WglArg.float('factor', -Math.PI/16)),
Matrix.generateDiagonal(16, i => Complex.polar(1, -i*Math.PI/16)));
});

suite.testUsingWebGL('DynamicPhaseGradientFamily', () => {
assertThatGateActsLikePhaser(
PhaseGradientGates.DynamicPhaseGradientFamily.ofSize(3),
k => 0.3*k,
0.3);

assertThatGateActsLikePhaser(
PhaseGradientGates.DynamicPhaseDegradientFamily.ofSize(2),
k => -0.1*k,
0.1);
});

0 comments on commit ce13cad

Please sign in to comment.