Skip to content

Commit

Permalink
Analyze subgroups before disabling permutation gates to prevent mixin…
Browse files Browse the repository at this point in the history
…g measured and coherent qubits
  • Loading branch information
Strilanc committed Jun 8, 2018
1 parent 5c6167b commit a9205f0
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 7 deletions.
34 changes: 33 additions & 1 deletion src/circuit/Gate.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ class Gate {
* @type {undefined | !function(!int) : !int}
*/
this.knownBitPermutationFunc = undefined;
/**
* When a permutation factors into sub-permutations over subsets of the bits, this map indexes each bit with
* an id for the group that it belongs to.
* @type {!Array.<!int>}
*/
this.knownBitPermutationGroupMasks = undefined;
/**
* Indicates that a gate is a phasing function, and that it phases each computation basis state by the amount
* returned by this function.
Expand Down Expand Up @@ -278,6 +284,7 @@ class Gate {
g.knownPermutationFuncTakingInputs = this.knownPermutationFuncTakingInputs;
g.customColumnContextProvider = this.customColumnContextProvider;
g.customDisableReasonFinder = this.customDisableReasonFinder;
g.knownBitPermutationGroupMasks = this.knownBitPermutationGroupMasks;
return g;
}

Expand Down Expand Up @@ -568,11 +575,12 @@ class GateBuilder {
* Provides a function equivalent to how the gate rearranges wires, for checking in tests if the gate's behavior is
* correct.
* @param {!function(!int) : !int} knownBitPermutationFunc Returns the output of the permutation for a
* given input, assuming the gate is exactly sized to the overall circuit.
* given input, assuming the gate is exactly sized to the overall circuit.
* @returns {!GateBuilder}
*/
setKnownEffectToBitPermutation(knownBitPermutationFunc) {
this.gate.knownBitPermutationFunc = knownBitPermutationFunc;
this.gate.knownBitPermutationGroupMasks = permutationGrouping(knownBitPermutationFunc, this.gate.height);
this.gate._isDefinitelyUnitary = true;
this.gate._stableDuration = Infinity;
this.gate._hasNoEffect = false;
Expand Down Expand Up @@ -928,4 +936,28 @@ class GateBuilder {
}
}

/**
* @param {!function(!int) : !int} knownBitPermutationFunc Returns the output of the permutation for a
* given input, assuming the gate is exactly sized to the overall circuit.
* @param {!int} height
* @returns {!Array.<!int>}
*/
function permutationGrouping(knownBitPermutationFunc, height) {
let seen = new Set();
let result = [];
for (let i = 0; i < height; i++) {
let mask = 0;
let j = i;
while (!seen.has(j)) {
seen.add(j);
mask |= 1 << j;
j = knownBitPermutationFunc(j);
}
if (mask !== 0) {
result.push(mask);
}
}
return result;
}

export {Gate, GateBuilder}
43 changes: 37 additions & 6 deletions src/circuit/GateColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ class GateColumn {
return false;
}

/**
* @returns {!int}
*/
controlMask() {
let mask = 0;
for (let i = 0; i < this.gates.length; i++) {
if (this.gates[i] !== undefined &&
this.gates[i].definitelyHasNoEffect() &&
this.gates[i].isControl()) {
mask |= 1 << i;
}
}
return mask;
}

/**
* @param {!int} inputMeasureMask
* @param {!int} row
Expand Down Expand Up @@ -170,25 +185,41 @@ class GateColumn {
let g = this.gates[row];
let mask = ((1 << g.height) - 1) << row;
let maskMeasured = mask & inputMeasureMask;
if (maskMeasured !== 0) {
if (maskMeasured !== 0 && g.knownBitPermutationFunc === undefined) {
// Don't try to superpose measured qubits.
if (g.effectMightCreateSuperpositions()) {
return "no\nremix\n(sorry)";
}

// Don't try to mix measured and coherent qubits, or coherently mix measured qubits.
if (g.effectMightPermutesStates()) {
// Only permutations that respect bit boundaries can be performed on mixed qubits.
if (maskMeasured !== mask && (g.knownBitPermutationFunc === undefined ||
this.hasMeasuredControl(inputMeasureMask))) {
if (maskMeasured !== mask || this.hasCoherentControl(inputMeasureMask)) {
return "no\nremix\n(sorry)";
}
}
}

// Permutations affecting classical states can't have quantum controls.
if (this.hasCoherentControl(inputMeasureMask)) {
// Check permutation subgroups for bad mixing of measured and coherent qubits.
if (g.knownBitPermutationGroupMasks !== undefined) {
for (let maskGroup of g.knownBitPermutationGroupMasks) {
let isSingleton = ((maskGroup - 1) & maskGroup) === 0;
if (isSingleton) {
continue;
}

maskGroup <<= row;
let hasCoherentQubits = (maskGroup & inputMeasureMask) !== maskGroup;
let hasMeasuredQubits = (maskGroup & inputMeasureMask) !== 0;
let coherentControl = this.hasCoherentControl(inputMeasureMask);
let controlled = this.hasControl(inputMeasureMask);
let coherentControlledMixingOfMeasured = hasMeasuredQubits && coherentControl;
let controlledMixingOfCoherentAndMeasured = hasCoherentQubits && hasMeasuredQubits && controlled;
if (coherentControlledMixingOfMeasured || controlledMixingOfCoherentAndMeasured) {
return "no\nremix\n(sorry)";
}
}
}

return undefined;
}

Expand Down
60 changes: 60 additions & 0 deletions test/circuit/CircuitDefinition.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,66 @@ suite.test("gateAtLocIsDisabledReason", () => {
bad(1, 0, `MR`, ['R', Gates.Detectors.XDetectControlClear]);
bad(1, 0, `MR`, ['R', Gates.Detectors.YDetectControlClear]);
good(1, 0, `MR`, ['R', Gates.Detectors.ZDetectControlClear]);

// Permutation sub-groups.
good(2, 0, `--P-
--/-
--/-
--/-
H-●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
good(2, 0, `-MP-
--/-
--/-
-M/-
H-●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
good(2, 0, `--P-
--/-
--/-
-M/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
good(2, 0, `-MP-
--/-
--/-
-M/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
good(2, 0, `--P-
-M/-
-M/-
--/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
good(2, 0, `-MP-
-M/-
-M/-
-M/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
bad(2, 0, `--P-
-M/-
-M/-
--/-
H-●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
bad(2, 0, `--P-
-M/-
--/-
--/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);

// Non-trivial subgroup.
good(2, 0, `--P-
-M/-
-M/-
--/-
-M/-
--/-
--/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
bad(2, 0, `--P-
-M/-
--/-
-M/-
-M/-
--/-
--/-
HM●-`, ['P', Gates.InterleaveBitsGates.InterleaveBitsGateFamily]);
});

suite.test("gateAtLocIsDisabledReason_controls", () => {
Expand Down

0 comments on commit a9205f0

Please sign in to comment.