Skip to content

Commit

Permalink
Merge pull request Strilanc#384 from Strilanc/dev
Browse files Browse the repository at this point in the history
Version 2.1
  • Loading branch information
Strilanc authored Sep 19, 2017
2 parents fd68b69 + ad56641 commit eaad86f
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 31 deletions.
2 changes: 1 addition & 1 deletion html/quirk.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
 
 
 
<span style="color:#BBB">Version 2.0</span>
<span style="color:#BBB">Version 2.1</span>
</div>

<!-- Circuit drawing area -->
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"title": "Quirk",
"description": "A drag-and-drop toy for exploring and understanding small quantum circuits.",
"license": "Apache-2.0",
"version": "2.0.0",
"version": "2.1.0",
"homepage": "https://github.com/Strilanc/Quirk",
"bugs": {
"url": "https://github.com/Strilanc/Quirk/issues"
Expand Down
27 changes: 19 additions & 8 deletions src/circuit/KetShaderUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,31 @@ const ketShaderPermute = (head, body, span=null) => ketShader(
span);

/**
* @param {!String} head
* @param {!String} body
* @param {null|!int=null} span
* Returns a shader that multiplies each of the amplitudes in a superposition by computed phase factors.
*
* @param {!String} head Header code defining shader methods, uniforms, etc.
* @param {!String} body The body of a shader method returning the number of radians to phase by.
* @param {null|!int=null} span The number of qubits this operation applies to, if known ahead of time.
* @return {!{withArgs: !function(args: ...!WglArg) : !WglConfiguredShader}}
*/
const ketShaderPhase = (head, body, span=null) => ketShader(
head + `vec2 _ketgen_phase_for(float out_id) { ${body} }`,
'return cmul(amp, _ketgen_phase_for(out_id));',
`${head}
float _ketgen_phase_for(float out_id) {
${body}
}
`,
`
float angle = _ketgen_phase_for(out_id);
return cmul(amp, vec2(cos(angle), sin(angle)));
`,
span);

/**
* @param {!CircuitEvalContext} ctx
* @param {undefined|!int=undefined} span
* @param {undefined|!Array.<!string>} input_letters
* Determines some arguments to give to a shader produced by one of the ketShader methods.
*
* @param {!CircuitEvalContext} ctx The context in which the ket shader is being applied.
* @param {undefined|!int=undefined} span The number of qubits this shader applies to (if wasn't known ahead of time).
* @param {undefined|!Array.<!string>} input_letters The input gates that this shader cares about.
* @returns {!Array.<!WglArg>}
*/
function ketArgs(ctx, span=undefined, input_letters=[]) {
Expand Down
4 changes: 2 additions & 2 deletions src/gates/CycleBitsGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ CycleBitsGates.CycleBitsFamily = Gate.buildFamily(2, 16, (span, builder) => buil
CycleBitsGates.ReverseCycleBitsFamily = Gate.buildFamily(2, 16, (span, builder) => builder.
setSerializedId(">>" + span).
setSymbol(">>>").
setSymbol("Right Rotate").
setTitle("Rotates bits upward.").
setTitle("Right Rotate").
setBlurb("Rotates bits upward.").
setDrawer(cyclePainter(true)).
setTooltipMatrixFunc(() => makeCycleBitsMatrix(-1, span)).
setActualEffectToShaderProvider(ctx => cycleBitsShader(ctx, span, -1)).
Expand Down
3 changes: 1 addition & 2 deletions src/gates/FourierTransformGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ const CONTROLLED_PHASE_GRADIENT_SHADER = ketShaderPhase(
`
float hold = floor(out_id * 2.0 / span);
float step = mod(out_id, span / 2.0);
float angle = hold * step * factor * 6.2831853071795864769 / span;
return vec2(cos(angle), sin(angle));
return hold * step * factor * 6.2831853071795864769 / span;
`);

const FOURIER_TRANSFORM_MATRIX_MAKER = span =>
Expand Down
2 changes: 1 addition & 1 deletion src/gates/MultiplyAccumulateGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,4 @@ MultiplyAccumulateGates.all = [
...MultiplyAccumulateGates.SquareSubtractInputFamily.all,
];

export {MultiplyAccumulateGates, BIG_MUL_MOD_SHADER_CODE}
export {MultiplyAccumulateGates, BIG_MUL_MOD_SHADER_CODE, MUL_STEP}
3 changes: 1 addition & 2 deletions src/gates/ParametrizedRotationGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ const Z_TO_A_SHADER = ketShaderPhase(
${ketInputGateShaderCode('A')}
`,
`
float angle = read_input_A() * out_id * factor / _gen_input_span_A;
return vec2(cos(angle), sin(angle));
return read_input_A() * out_id * factor / _gen_input_span_A;
`);

ParametrizedRotationGates.XToA = new GateBuilder().
Expand Down
22 changes: 19 additions & 3 deletions src/gates/PhaseGradientGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {Config} from "src/Config.js";
import {Gate} from "src/circuit/Gate.js"
import {GatePainting} from "src/draw/GatePainting.js"
import {ketArgs, ketShaderPhase} from "src/circuit/KetShaderUtil.js"
import {MUL_STEP} from "src/gates/MultiplyAccumulateGates.js"
import {WglArg} from "src/webgl/WglArg.js"

const PHASE_GRADIENT_SHADER = ketShaderPhase(
'uniform float factor;',
`
float angle = out_id * factor;
return vec2(cos(angle), sin(angle));
uniform float factor;
/// Scales an angle by an integer factor.
/// Performs the multiplication gradually, to avoid losing precision.
float angle_mul(float base_angle, float whole_factor) {
float result = 0.0;
for (int k = 0; k < ${Math.ceil(Config.MAX_WIRE_COUNT/MUL_STEP)}; k++) {
result += base_angle * mod(whole_factor, ${1<<MUL_STEP}.0);
result = mod(result, 6.283185307179586476925286766559);
whole_factor = floor(whole_factor / ${1<<MUL_STEP}.0);
base_angle = mod(base_angle * ${1<<MUL_STEP}.0, 6.283185307179586476925286766559);
}
return result;
}
`,
`
return angle_mul(factor, out_id);
`);

let PhaseGradientGates = {};
Expand Down
8 changes: 4 additions & 4 deletions src/gates/PostSelectionGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ PostSelectionGates.PostSelectOn = new GateBuilder().
/** @type {!Gate} */
PostSelectionGates.PostSelectAntiX = new GateBuilder().
setSerializedId("|+⟩⟨+|"). // The +/- drawing convention was switched, but the serialized id must stay the same.
setSymbol("|-⟩⟨-|").
setSymbol("|⊖⟩⟨⊖|").
setTitle("Postselect X-Off").
setBlurb("Keeps ON+OFF states, discards/retries ON-OFF states.").
setDrawer(POST_SELECT_DRAWER).
Expand All @@ -65,7 +65,7 @@ PostSelectionGates.PostSelectAntiX = new GateBuilder().
/** @type {!Gate} */
PostSelectionGates.PostSelectX = new GateBuilder().
setSerializedId("|-⟩⟨-|"). // The +/- drawing convention was switched, but the serialized id must stay the same.
setSymbol("|+⟩⟨+|").
setSymbol("|⊕⟩⟨⊕|").
setTitle("Postselect X-On").
setBlurb("Keeps ON-OFF states, discards/retries ON+OFF states.").
setDrawer(POST_SELECT_DRAWER).
Expand All @@ -75,7 +75,7 @@ PostSelectionGates.PostSelectX = new GateBuilder().
/** @type {!Gate} */
PostSelectionGates.PostSelectAntiY = new GateBuilder().
setSerializedId("|X⟩⟨X|"). // The cross/slash convention was switched, but the serialized id must stay the same.
setSymbol("|/⟩⟨/|").
setSymbol("|⊘⟩⟨⊘|").
setTitle("Postselect Y-Off").
setBlurb("Keeps ON+iOFF states, discards ON-iOFF states.").
setDrawer(POST_SELECT_DRAWER).
Expand All @@ -85,7 +85,7 @@ PostSelectionGates.PostSelectAntiY = new GateBuilder().
/** @type {!Gate} */
PostSelectionGates.PostSelectY = new GateBuilder().
setSerializedId("|/⟩⟨/|"). // The cross/slash convention was switched, but the serialized id must stay the same.
setSymbol("|X⟩⟨X|").
setSymbol("|⊗⟩⟨⊗|").
setTitle("Postselect Y-On").
setBlurb("Keeps ON-iOFF states, discards/retries ON+iOFF states.").
setDrawer(POST_SELECT_DRAWER).
Expand Down
41 changes: 35 additions & 6 deletions test/circuit/CircuitStats.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {Suite, assertThat, assertTrue} from "test/TestUtil.js"
import {CircuitStats} from "src/circuit/CircuitStats.js"

import {CircuitDefinition} from "src/circuit/CircuitDefinition.js"
import {Complex} from "src/math/Complex.js"
import {GateColumn} from "src/circuit/GateColumn.js"
import {Gates} from "src/gates/AllGates.js"
import {Matrix} from "src/math/Matrix.js"
Expand All @@ -41,7 +42,7 @@ const circuit = (diagram, ...extras) => CircuitDefinition.fromTextDiagram(new Ma
['-', undefined],
['+', undefined],
['|', undefined],
['/', undefined]
['/', null]
]), diagram);

suite.testUsingWebGL("empty", () => {
Expand Down Expand Up @@ -117,7 +118,7 @@ suite.testUsingWebGL('incoherent-amplitude-display', () => {
suite.testUsingWebGL('coherent-amplitude-display', () => {
let c = circuit(`-H-•-a/--
---X-//--
-H-------`, ['a', Gates.Displays.AmplitudeDisplayFamily.ofSize(2)]);
-H-------`, ['a', Gates.Displays.AmplitudeDisplayFamily]);
let stats = CircuitStats.fromCircuitAtTime(c, 0);
assertThat(stats.qubitDensityMatrix(Infinity, 0)).isApproximatelyEqualTo(Matrix.square(0.5, 0, 0, 0.5));
assertThat(stats.qubitDensityMatrix(Infinity, 1)).isApproximatelyEqualTo(Matrix.square(0.5, 0, 0, 0.5));
Expand All @@ -141,7 +142,7 @@ suite.testUsingWebGL('conditional-bloch-display', () => {

suite.testUsingWebGL('probability-display', () => {
let c = circuit(`-H-•-%-
---X-/-`, ['%', Gates.Displays.ProbabilityDisplayFamily.ofSize(2)]);
---X-/-`, ['%', Gates.Displays.ProbabilityDisplayFamily]);
let stats = CircuitStats.fromCircuitAtTime(c, 0);
assertThat(stats.qubitDensityMatrix(Infinity, 0)).isApproximatelyEqualTo(Matrix.square(0.5, 0, 0, 0.5));
assertThat(stats.customStatsForSlot(5, 0)).isApproximatelyEqualTo(
Expand All @@ -151,15 +152,15 @@ suite.testUsingWebGL('probability-display', () => {
suite.testUsingWebGL('controlled-multi-probability-display', () => {
let c = circuit(`---◦-
-H-%-
---/-`, ['%', Gates.Displays.ProbabilityDisplayFamily.ofSize(2)]);
---/-`, ['%', Gates.Displays.ProbabilityDisplayFamily]);
let stats = CircuitStats.fromCircuitAtTime(c, 0);
assertThat(stats.customStatsForSlot(3, 1)).isApproximatelyEqualTo(
Matrix.col(0.5, 0.5, 0, 0));
});

suite.testUsingWebGL('density-display', () => {
let c = circuit(`-d/-
-//-`, ['d', Gates.Displays.DensityMatrixDisplayFamily.ofSize(2)]);
-//-`, ['d', Gates.Displays.DensityMatrixDisplayFamily]);
let stats = CircuitStats.fromCircuitAtTime(c, 0);
assertThat(stats.customStatsForSlot(1, 0)).isApproximatelyEqualTo(
Matrix.square(
Expand All @@ -172,7 +173,7 @@ suite.testUsingWebGL('density-display', () => {
suite.testUsingWebGL('shifted-density-display', () => {
let c = circuit(`----
-d/-
-//-`, ['d', Gates.Displays.DensityMatrixDisplayFamily.ofSize(2)]);
-//-`, ['d', Gates.Displays.DensityMatrixDisplayFamily]);
let stats = CircuitStats.fromCircuitAtTime(c, 0);
assertThat(stats.customStatsForSlot(1, 1)).isApproximatelyEqualTo(
Matrix.square(
Expand Down Expand Up @@ -262,3 +263,31 @@ suite.testUsingWebGL('survival-rates-controlled-postselection', () => {
assertThat(stats.survivalRate(13)).isApproximatelyEqualTo(0.5);
assertThat(stats.survivalRate(14)).isApproximatelyEqualTo(0.5);
});

suite.testUsingWebGL('dynamic-phase-gradient-keeps-qubits-coherent', () => {
let stats = CircuitStats.fromCircuitAtTime(
circuit(`-H-P-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-
-H-/-`, ['P', Gates.PhaseGradientGates.DynamicPhaseGradientFamily]),
0.9);

// Check coherence of each qubit.
for (let i = 0; i < 16; i++) {
let [x, y, z] = stats.qubitDensityMatrix(Infinity, i).qubitDensityMatrixToBlochVector();
let r = x*x + y*y + z*z;
assertThat(r).withInfo({i, x, y, z}).isApproximatelyEqualTo(1);
}
});
2 changes: 1 addition & 1 deletion test/circuit/KetShaderUtil.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ suite.testUsingWebGL("ketShaderPermute", () => {
suite.testUsingWebGL("ketShaderPhase", () => {
let shader = ketShaderPhase(
'',
'return vec2(cos(out_id/10.0), sin(out_id/10.0));',
'return out_id/10.0;',
3);
assertThatCircuitShaderActsLikeMatrix(
ctx => shader.withArgs(...ketArgs(ctx)),
Expand Down

0 comments on commit eaad86f

Please sign in to comment.