diff --git a/package.json b/package.json index a20dd0e4..f55c4457 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "title": "Quirk", "description": "A drag-and-drop toy for exploring and understanding small quantum circuits.", "license": "Apache-2.0", - "version": "1.9.1", + "version": "2.0.0", "homepage": "https://github.com/Strilanc/Quirk", "bugs": { "url": "https://github.com/Strilanc/Quirk/issues" diff --git a/src/base/Util.js b/src/base/Util.js index 7923c0d1..fb55aa0a 100644 --- a/src/base/Util.js +++ b/src/base/Util.js @@ -104,18 +104,17 @@ class Util { /** * @param {!int} n - * @returns {!int} + * @returns {!int} A value p such that 2**(p-1) < n <= 2**p. */ static ceilLg2(n) { if (n <= 1) { return 0; } let p = Math.ceil(Math.log2(n)); - let v = 1 << p; - if (v < n) { + if (1<

= n*2) { + if (n <= 1<<(p-1)) { return p - 1; } return p; @@ -123,18 +122,17 @@ class Util { /** * @param {!int} n - * @returns {!int} + * @returns {!int} A value p such that 2**p <= n < 2**(p+1). */ static floorLg2(n) { if (n <= 1) { return 0; } let p = Math.floor(Math.log2(n)); - let v = 1 << p; - if (v*2 < n) { + if (1<<(p+1) <= n) { return p + 1; } - if (v > n) { + if (n < 1<Output gate connections. - for (let letter of ["A", "B"]) { + for (let letter of Gates.InputGates.Letters) { let key = `Input Range ${letter}`; let altInKey = `Input Default ${letter}`; let altOutKey = `Input NO_DEFAULT Range ${letter}`; diff --git a/src/gates/AllGates.js b/src/gates/AllGates.js index ee0fd925..315caee5 100644 --- a/src/gates/AllGates.js +++ b/src/gates/AllGates.js @@ -14,7 +14,8 @@ import {HalfTurnGates} from "src/gates/HalfTurnGates.js" import {InputGates} from "src/gates/InputGates.js" import {InterleaveBitsGates} from "src/gates/InterleaveBitsGates.js" import {MeasurementGate} from "src/gates/MeasurementGate.js" -import {ModularArithmeticGates} from "src/gates/ModularArithmeticGates.js" +import {ModularIncrementGates} from "src/gates/ModularIncrementGates.js" +import {ModularAdditionGates} from "src/gates/ModularAdditionGates.js" import {ModularMultiplicationGates} from "src/gates/ModularMultiplicationGates.js" import {MultiplicationGates} from "src/gates/MultiplicationGates.js" import {MultiplyAccumulateGates} from "src/gates/MultiplyAccumulateGates.js" @@ -72,7 +73,8 @@ Gates.FourierTransformGates = FourierTransformGates; Gates.HalfTurns = HalfTurnGates; Gates.InputGates = InputGates; Gates.InterleaveBitsGates = InterleaveBitsGates; -Gates.ModularArithmeticGates = ModularArithmeticGates; +Gates.ModularIncrementGates = ModularIncrementGates; +Gates.ModularAdditionGates = ModularAdditionGates; Gates.ModularMultiplicationGates = ModularMultiplicationGates; Gates.MultiplicationGates = MultiplicationGates; Gates.MultiplyAccumulateGates = MultiplyAccumulateGates; @@ -118,7 +120,8 @@ Gates.KnownToSerializer = [ ...FourierTransformGates.all, ...HalfTurnGates.all, ...InterleaveBitsGates.all, - ...ModularArithmeticGates.all, + ...ModularAdditionGates.all, + ...ModularIncrementGates.all, ...ModularMultiplicationGates.all, ...MultiplicationGates.all, ...MultiplyAccumulateGates.all, @@ -282,8 +285,8 @@ Gates.BottomToolboxGroups = [ { hint: "Modular", gates: [ - ModularArithmeticGates.IncrementModRFamily.ofSize(2), ModularArithmeticGates.DecrementModRFamily.ofSize(2), - ModularArithmeticGates.PlusAModRFamily.ofSize(2), ModularArithmeticGates.MinusAModRFamily.ofSize(2), + ModularIncrementGates.IncrementModRFamily.ofSize(2), ModularIncrementGates.DecrementModRFamily.ofSize(2), + ModularAdditionGates.PlusAModRFamily.ofSize(2), ModularAdditionGates.MinusAModRFamily.ofSize(2), ModularMultiplicationGates.TimesAModRFamily.ofSize(2), ModularMultiplicationGates.TimesAModRInverseFamily.ofSize(2), ModularMultiplicationGates.TimesBToTheAModRFamily.ofSize(2), diff --git a/src/gates/ArithmeticGates.js b/src/gates/ArithmeticGates.js index e86b73f4..8dae5425 100644 --- a/src/gates/ArithmeticGates.js +++ b/src/gates/ArithmeticGates.js @@ -42,7 +42,7 @@ ArithmeticGates.IncrementFamily = Gate.buildFamily(1, 16, (span, builder) => bui ArithmeticGates.DecrementFamily = Gate.buildFamily(1, 16, (span, builder) => builder. setSerializedId("dec" + span). - setSymbol("-1"). + setSymbol("−1"). setTitle("Decrement Gate"). setBlurb("Subtracts 1 from the little-endian number represented by a block of qubits."). setActualEffectToShaderProvider(ctx => offsetShader.withArgs( diff --git a/src/gates/InputGates.js b/src/gates/InputGates.js index d5256704..78fe8a9d 100644 --- a/src/gates/InputGates.js +++ b/src/gates/InputGates.js @@ -90,7 +90,7 @@ let makeSetInputGate = key => new GateBuilder(). return oldGate; } - let val = Number.parseInt(txt); + let val = parseInt(txt); if (!Number.isInteger(val) || val < 0 || val >= 1<<16) { alert(`'${txt}' isn't an integer between 0 and 65535. Keeping ${oldGate.param}.`); return oldGate; @@ -109,6 +109,7 @@ InputGates.InputRevBFamily = makeInputGate('B', true); InputGates.SetA = makeSetInputGate('A'); InputGates.SetB = makeSetInputGate('B'); InputGates.SetR = makeSetInputGate('R'); +InputGates.Letters = ["A", "B", "R"]; InputGates.all = [ ...InputGates.InputAFamily.all, diff --git a/src/gates/ModularAdditionGates.js b/src/gates/ModularAdditionGates.js new file mode 100644 index 00000000..5189e068 --- /dev/null +++ b/src/gates/ModularAdditionGates.js @@ -0,0 +1,63 @@ +import {Gate} from "src/circuit/Gate.js" +import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "src/circuit/KetShaderUtil.js" +import {Util} from "src/base/Util.js" +import {WglArg} from "src/webgl/WglArg.js" +import {modulusTooBigChecker} from "src/gates/ModularIncrementGates.js" + +let ModularAdditionGates = {}; + +const MODULAR_ADDITION_SHADER = ketShaderPermute( + ` + uniform float factor; + ${ketInputGateShaderCode('A')} + ${ketInputGateShaderCode('R')} + `, + ` + float r = read_input_R(); + if (out_id >= r) { + return out_id; + } + float d = read_input_A(); + d *= factor; + d = mod(d, r); + float result = mod(out_id + r - d, r); + + // Despite sanity, I consistently get result=33 instead of result=0 when out_id=0, d=0, r=33. + // HACK: Fix it by hand. + if (result >= r) { + result -= r; + } + + return result; + `); + +ModularAdditionGates.PlusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. + setSerializedId("+AmodR" + span). + setSymbol("+A\nmod R"). + setTitle("Modular Addition Gate"). + setBlurb("Adds input A into the target, mod input R.\nOnly affects values below R."). + setRequiredContextKeys("Input Range A", "Input Range R"). + setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). + setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( + ...ketArgs(ctx, span, ['A', 'R']), + WglArg.float("factor", +1))). + setKnownEffectToParametrizedPermutation((t, a, b) => t < b ? (t + a) % b : t)); + +ModularAdditionGates.MinusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. + setSerializedId("-AmodR" + span). + setSymbol("−A\nmod R"). + setTitle("Modular Subtraction Gate"). + setBlurb("Subtracts input A out of the target, mod input R.\nOnly affects values below R."). + setRequiredContextKeys("Input Range A", "Input Range R"). + setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). + setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( + ...ketArgs(ctx, span, ['A', 'R']), + WglArg.float("factor", -1))). + setKnownEffectToParametrizedPermutation((t, a, b) => t < b ? Util.properMod(t - a, b) : t)); + +ModularAdditionGates.all = [ + ...ModularAdditionGates.PlusAModRFamily.all, + ...ModularAdditionGates.MinusAModRFamily.all, +]; + +export {ModularAdditionGates} diff --git a/src/gates/ModularArithmeticGates.js b/src/gates/ModularArithmeticGates.js deleted file mode 100644 index f99c651c..00000000 --- a/src/gates/ModularArithmeticGates.js +++ /dev/null @@ -1,110 +0,0 @@ -import {Gate} from "src/circuit/Gate.js" -import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "src/circuit/KetShaderUtil.js" -import {Util} from "src/base/Util.js" -import {WglArg} from "src/webgl/WglArg.js" - -let ModularArithmeticGates = {}; - -/** - * @param {!string} inputKey - * @param {!int} span - * @returns {!function(!GateCheckArgs) : (undefined|!string)} - */ -let modulusTooBigChecker = (inputKey, span) => args => { - let r = args.context.get('Input Range ' + inputKey); - let d = args.context.get('Input Default ' + inputKey); - if (r !== undefined && r.length > span) { - return "mod\ntoo\nbig"; - } - if (r === undefined && d !== undefined && d > 1<= r - ? out_id - // HACK: sometimes mod(value-equal-to-r, r) returns r instead of 0. The perturbation works around it. - : floor(mod(out_id + r - amount, r - 0.000001));`); - -ModularArithmeticGates.IncrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. - setSerializedId("incmodR" + span). - setSymbol("+1\nmod R"). - setTitle("Modular Increment Gate"). - setBlurb("Adds 1 into the target, but wraps R-1 to 0.\n" + - "Only affects values less than R."). - setRequiredContextKeys("Input Range R"). - setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). - setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( - ...ketArgs(ctx, span, ['R']), - WglArg.float("amount", +1))). - setKnownEffectToParametrizedPermutation((t, a) => t < a ? (t + 1) % a : t)); - -ModularArithmeticGates.DecrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. - setSerializedId("decmodR" + span). - setSymbol("−1\nmod R"). - setTitle("Modular Decrement Gate"). - setBlurb("Subtracts 1 out of the target, but wraps 0 to R-1.\n" + - "Only affects values less than R."). - setRequiredContextKeys("Input Range R"). - setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). - setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( - ...ketArgs(ctx, span, ['R']), - WglArg.float("amount", -1))). - setKnownEffectToParametrizedPermutation((t, a) => t < a ? Util.properMod(t - 1, a) : t)); - -const MODULAR_ADDITION_SHADER = ketShaderPermute( - ` - uniform float factor; - ${ketInputGateShaderCode('A')} - ${ketInputGateShaderCode('R')} - `, - ` - float d = read_input_A(); - float r = read_input_R(); - d *= factor; - d = mod(d, r); - return out_id >= r - ? out_id - // HACK: sometimes mod(value-equal-to-r, r) returns r instead of 0. The perturbation works around it. - : floor(mod(out_id + r - d, r - 0.000001) + 0.5);`); - -ModularArithmeticGates.PlusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. - setSerializedId("+AmodR" + span). - setSymbol("+A\nmod R"). - setTitle("Modular Addition Gate"). - setBlurb("Adds input A into the target, mod input R.\nOnly affects values below R."). - setRequiredContextKeys("Input Range A", "Input Range R"). - setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). - setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( - ...ketArgs(ctx, span, ['A', 'R']), - WglArg.float("factor", +1))). - setKnownEffectToParametrizedPermutation((t, a, b) => t < b ? (t + a) % b : t)); - -ModularArithmeticGates.MinusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. - setSerializedId("-AmodR" + span). - setSymbol("−A\nmod R"). - setTitle("Modular Subtraction Gate"). - setBlurb("Subtracts input A out of the target, mod input R.\nOnly affects values below R."). - setRequiredContextKeys("Input Range A", "Input Range R"). - setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). - setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( - ...ketArgs(ctx, span, ['A', 'R']), - WglArg.float("factor", -1))). - setKnownEffectToParametrizedPermutation((t, a, b) => t < b ? Util.properMod(t - a, b) : t)); - -ModularArithmeticGates.all = [ - ...ModularArithmeticGates.IncrementModRFamily.all, - ...ModularArithmeticGates.DecrementModRFamily.all, - ...ModularArithmeticGates.PlusAModRFamily.all, - ...ModularArithmeticGates.MinusAModRFamily.all, -]; - -export {ModularArithmeticGates, modulusTooBigChecker} diff --git a/src/gates/ModularIncrementGates.js b/src/gates/ModularIncrementGates.js new file mode 100644 index 00000000..366b6955 --- /dev/null +++ b/src/gates/ModularIncrementGates.js @@ -0,0 +1,68 @@ +import {Gate} from "src/circuit/Gate.js" +import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "src/circuit/KetShaderUtil.js" +import {Util} from "src/base/Util.js" +import {WglArg} from "src/webgl/WglArg.js" + +let ModularIncrementGates = {}; + +/** + * @param {!string} inputKey + * @param {!int} span + * @returns {!function(!GateCheckArgs) : (undefined|!string)} + */ +let modulusTooBigChecker = (inputKey, span) => args => { + let r = args.context.get('Input Range ' + inputKey); + let d = args.context.get('Input Default ' + inputKey); + if (r !== undefined && r.length > span) { + return "mod\ntoo\nbig"; + } + if (r === undefined && d !== undefined && d > 1<= r + ? out_id + // HACK: sometimes mod(value-equal-to-r, r) returns r instead of 0. The perturbation works around it. + : floor(mod(out_id + r - amount, r - 0.000001));`); + +ModularIncrementGates.IncrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. + setSerializedId("incmodR" + span). + setSymbol("+1\nmod R"). + setTitle("Modular Increment Gate"). + setBlurb("Adds 1 into the target, but wraps R-1 to 0.\n" + + "Only affects values less than R."). + setRequiredContextKeys("Input Range R"). + setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). + setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( + ...ketArgs(ctx, span, ['R']), + WglArg.float("amount", +1))). + setKnownEffectToParametrizedPermutation((t, a) => t < a ? (t + 1) % a : t)); + +ModularIncrementGates.DecrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. + setSerializedId("decmodR" + span). + setSymbol("−1\nmod R"). + setTitle("Modular Decrement Gate"). + setBlurb("Subtracts 1 out of the target, but wraps 0 to R-1.\n" + + "Only affects values less than R."). + setRequiredContextKeys("Input Range R"). + setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). + setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( + ...ketArgs(ctx, span, ['R']), + WglArg.float("amount", -1))). + setKnownEffectToParametrizedPermutation((t, a) => t < a ? Util.properMod(t - 1, a) : t)); + +ModularIncrementGates.all = [ + ...ModularIncrementGates.IncrementModRFamily.all, + ...ModularIncrementGates.DecrementModRFamily.all, +]; + +export {ModularIncrementGates, modulusTooBigChecker} diff --git a/src/gates/ModularMultiplicationGates.js b/src/gates/ModularMultiplicationGates.js index c7487f47..4bba40d6 100644 --- a/src/gates/ModularMultiplicationGates.js +++ b/src/gates/ModularMultiplicationGates.js @@ -5,30 +5,21 @@ import { ketShaderPermute, ketInputGateShaderCode } from "src/circuit/KetShaderUtil.js" -import {modulusTooBigChecker} from "src/gates/ModularArithmeticGates.js" +import {modulusTooBigChecker} from "src/gates/ModularIncrementGates.js" +import {BIG_MUL_MOD_SHADER_CODE} from "src/gates/MultiplyAccumulateGates.js" import {Util} from "src/base/Util.js" import {WglArg} from "src/webgl/WglArg.js" let ModularMultiplicationGates = {}; +const MUL_STEP = 6; + const MODULAR_INVERSE_SHADER_CODE = ` vec2 _mod_mul_step(vec2 v, float q) { return vec2(v.y - q * v.x, v.x); } - // Avoids large multiplications that lose precision. - float times_mod(float b, float f, float modulus) { - float t = 0.0; - for (int k = 0; k < ${Config.MAX_WIRE_COUNT}; k++) { - if (mod(f, 2.0) == 1.0) { - f -= 1.0; - t = mod(t + b, modulus); - } - b = mod(b * 2.0, modulus); - f /= 2.0; - } - return t; - } + ${BIG_MUL_MOD_SHADER_CODE} float modular_multiplicative_inverse(float value, float modulus) { vec2 s = vec2(0.0, 1.0); @@ -69,9 +60,9 @@ const POW_MOD_SHADER_CODE = ` for (int k = 0; k < ${Config.MAX_WIRE_COUNT}; k++) { if (mod(exponent, 2.0) == 1.0) { exponent -= 1.0; - f = times_mod(f, base, modulus); + f = big_mul_mod(f, base, modulus); } - base = times_mod(base, base, modulus); + base = big_mul_mod(base, base, modulus); exponent /= 2.0; } return f; @@ -171,7 +162,7 @@ const MODULAR_MULTIPLICATION_SHADER = ketShaderPermute( if (v == -1.0 || out_id >= modulus) { return out_id; } - return times_mod(out_id, v, modulus); + return big_mul_mod(out_id, v, modulus); `); const MODULAR_INVERSE_MULTIPLICATION_SHADER = ketShaderPermute( @@ -187,7 +178,7 @@ const MODULAR_INVERSE_MULTIPLICATION_SHADER = ketShaderPermute( if (modular_multiplicative_inverse(input_a, modulus) == -1.0 || out_id >= modulus) { return out_id; } - return times_mod(out_id, input_a, modulus); + return big_mul_mod(out_id, input_a, modulus); `); const MODULAR_POWER_MULTIPLICATION_SHADER = ketShaderPermute( @@ -206,7 +197,7 @@ const MODULAR_POWER_MULTIPLICATION_SHADER = ketShaderPermute( if (f == -1.0 || out_id >= modulus) { return out_id; } - return times_mod(out_id, f, modulus); + return big_mul_mod(out_id, f, modulus); `); ModularMultiplicationGates.TimesAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. diff --git a/src/gates/MultiplicationGates.js b/src/gates/MultiplicationGates.js index c77990d9..d01b64bd 100644 --- a/src/gates/MultiplicationGates.js +++ b/src/gates/MultiplicationGates.js @@ -20,7 +20,7 @@ const MULTIPLICATION_SHADER = ketShaderPermute( if (v == -1.0) { return out_id; } - return mod(out_id * v, span); + return big_mul_mod(out_id, v, span); `); const INVERSE_MULTIPLICATION_SHADER = ketShaderPermute( @@ -34,7 +34,7 @@ const INVERSE_MULTIPLICATION_SHADER = ketShaderPermute( if (modular_multiplicative_inverse(input_a, span) == -1.0) { return out_id; } - return mod(out_id * input_a, span); + return big_mul_mod(out_id, input_a, span); `); MultiplicationGates.TimesAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. diff --git a/src/gates/MultiplyAccumulateGates.js b/src/gates/MultiplyAccumulateGates.js index 9080c959..ab55c7c9 100644 --- a/src/gates/MultiplyAccumulateGates.js +++ b/src/gates/MultiplyAccumulateGates.js @@ -1,3 +1,4 @@ +import {Config} from "src/Config.js"; import {Gate} from "src/circuit/Gate.js" import {GatePainting} from "src/draw/GatePainting.js" import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "src/circuit/KetShaderUtil.js" @@ -22,16 +23,34 @@ const makeScaledMultiplyAddPermutation = (span, scaleFactor) => e => { return a | (b << sa) | (c << (sa+sb)); }; +const MUL_STEP = 6; +const BIG_MUL_MOD_SHADER_CODE = ` + // Avoids large multiplications that lose precision. + float big_mul_mod(float b, float f, float modulus) { + float t = 0.0; + float r; + for (int k = 0; k < ${Math.ceil(Config.MAX_WIRE_COUNT/MUL_STEP)}; k++) { + r = mod(f, ${1< builder. @@ -121,4 +140,4 @@ MultiplyAccumulateGates.all = [ ...MultiplyAccumulateGates.SquareSubtractInputFamily.all, ]; -export {MultiplyAccumulateGates} +export {MultiplyAccumulateGates, BIG_MUL_MOD_SHADER_CODE} diff --git a/src/gates/XorGates.js b/src/gates/XorGates.js index d2a3f347..a26c4a30 100644 --- a/src/gates/XorGates.js +++ b/src/gates/XorGates.js @@ -18,7 +18,7 @@ const XOR_SHADER = ketShaderPermute( } return result;`); -XorGates.XorAFamily = Gate.buildFamily(1, 8, (span, builder) => builder. +XorGates.XorAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. setSerializedId("^=A" + span). setSymbol("⊕A"). setTitle("Xor Gate [input A]"). diff --git a/src/main.js b/src/main.js index 6d775b85..1dab6d31 100644 --- a/src/main.js +++ b/src/main.js @@ -137,9 +137,14 @@ redrawThrottle = new CooldownThrottle(redrawNow, Config.REDRAW_COOLDOWN_MILLIS, window.addEventListener('resize', () => redrawThrottle.trigger(), false); displayed.observable().subscribe(() => redrawThrottle.trigger()); +/** @type {undefined|!string} */ +let clickDownGateButtonKey = undefined; canvasDiv.addEventListener('click', ev => { let pt = eventPosRelativeTo(ev, canvasDiv); let curInspector = displayed.get(); + if (curInspector.isHandOverButtonKey() !== clickDownGateButtonKey) { + return; + } let clicked = syncArea(curInspector.withHand(curInspector.hand.withPos(pt))).tryClick(); if (clicked !== undefined) { revision.commit(clicked.snapshot()); @@ -156,7 +161,8 @@ watchDrags(canvasDiv, let oldInspector = displayed.get(); let newHand = oldInspector.hand.withPos(pt); let newInspector = syncArea(oldInspector.withHand(newHand)); - if (newInspector.isHandOverButton()) { + clickDownGateButtonKey = newInspector.isHandOverButtonKey(); + if (clickDownGateButtonKey !== undefined) { displayed.set(newInspector); return; } diff --git a/src/ui/DisplayedInspector.js b/src/ui/DisplayedInspector.js index 90133a22..1a50cffe 100644 --- a/src/ui/DisplayedInspector.js +++ b/src/ui/DisplayedInspector.js @@ -111,11 +111,14 @@ class DisplayedInspector { } /** - * @returns {!boolean} + * @returns {undefined|!string} */ - isHandOverButton() { - return this.hand.pos !== undefined && - this.displayedCircuit.findGateWithButtonContaining(this.hand.pos) !== undefined; + isHandOverButtonKey() { + if (this.hand.pos === undefined) { + return undefined; + } + let pos = this.displayedCircuit.findGateWithButtonContaining(this.hand.pos); + return pos === undefined ? undefined : pos.col + ':' + pos.row; } /** diff --git a/src/ui/menu.js b/src/ui/menu.js index a6b7659b..9eb05251 100644 --- a/src/ui/menu.js +++ b/src/ui/menu.js @@ -181,6 +181,26 @@ const symmetryBreakingLink = { {"id":"~57au","name":"disagree","matrix":"{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}"} ] }; +const shorLink = { + "cols":[ + [1,1,1,1,1,1,1,1,1,1,"~mdaf",1,1,1,"~h1nm"], + [1,1,1,1,1,1,1,1,1,1,{"id":"setR","arg":55},1,1,1,{"id":"setB","arg":26}], + [], + ["H","H","H","H","H","H","H","H","H","H","X"], + ["inputA10",1,1,1,1,1,1,1,1,1,"*BToAmodR6"], + ["QFT†10"], + [1,1,1,1,"~mjoi",1,1,1,1,1,1,1,"~mjoi"], + ["Chance10",1,1,1,1,1,1,1,1,1,"Chance6"], + [1,1,1,1,"~a6uq"], + ["Sample10"] + ], + "gates":[ + {"id":"~h1nm","name":"guess:","matrix":"{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}"}, + {"id":"~mdaf","name":"input:","matrix":"{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}"}, + {"id":"~a6uq","name":"samples:","matrix":"{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}"}, + {"id":"~mjoi","name":"state:","matrix":"{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}"} + ] +}; /** * @param {!Revision} revision @@ -219,8 +239,10 @@ function initMenu(revision, obsIsAnyOverlayShowing) { const symmetryBreakAnchor = /** @type {!HTMLAnchorElement} */ document.getElementById('example-symmetry-break'); const chshTestAnchor = /** @type {!HTMLAnchorElement} */ document.getElementById('example-chsh-test'); const qftAnchor = /** @type {!HTMLAnchorElement} */ document.getElementById('example-qft'); + const shorAnchor = /** @type {!HTMLAnchorElement} */ document.getElementById('example-anchor-shor'); for (let [a, t] of [[groverAnchor, groverLink], + [shorAnchor, shorLink], [teleportAnchor, teleportLink], [eraserAnchor, eraserLink], [additionAnchor, additionLink], diff --git a/template/export.partial.html b/template/export.partial.html index f6945b3e..1b42e0fd 100644 --- a/template/export.partial.html +++ b/template/export.partial.html @@ -1,5 +1,5 @@