Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions glue/crumble/circuit/circuit.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class Circuit {
replaceAll('#!pragma ERR', 'ERR').
replaceAll('#!pragma MARK', 'MARK').
replaceAll('#!pragma POLYGON', 'POLYGON').
replaceAll('#!pragma REVMARK', 'REVMARK').
replaceAll('_', ' ').
replaceAll('Q(', 'QUBIT_COORDS(').
replaceAll('DT', 'DETECTOR').
Expand Down
17 changes: 11 additions & 6 deletions glue/crumble/circuit/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {Operation} from "./operation.js"
import {GATE_MAP} from "../gates/gateset.js";
import {groupBy} from "../base/seq.js";

const MARKER_NAMES = ['MARKX', 'MARKY', 'MARKZ', 'REVMARKX', 'REVMARKY', 'REVMARKZ'];

class Layer {
constructor() {
this.id_ops = /** @type {!Map<!int, !Operation>} */ new Map();
Expand Down Expand Up @@ -216,9 +218,12 @@ class Layer {
* @param {!int} marker_index
* @returns {!Map<!int, !string>}
*/
id_pauliFrameAfter(before, marker_index) {
id_pauliFrameAfter(before, marker_index, reverse=false) {
let after = new Map();
let handled = new Set();
const MARKX_NAME = reverse ? 'REVMARKX' : 'MARKX';
const MARKY_NAME = reverse ? 'REVMARKY' : 'MARKY';
const MARKZ_NAME = reverse ? 'REVMARKZ' : 'MARKZ';

for (let k of before.keys()) {
let v = before.get(k);
Expand Down Expand Up @@ -253,7 +258,7 @@ class Layer {
}

for (let op of this.markers) {
if (op.gate.name === 'MARKX' && op.args[0] === marker_index) {
if (op.gate.name === MARKX_NAME && op.args[0] === marker_index) {
let key = op.id_targets[0];
let pauli = after.get(key);
if (pauli === undefined || pauli === 'I') {
Expand All @@ -266,7 +271,7 @@ class Layer {
pauli = 'Y';
}
after.set(key, pauli);
} else if (op.gate.name === 'MARKY' && op.args[0] === marker_index) {
} else if (op.gate.name === MARKY_NAME && op.args[0] === marker_index) {
let key = op.id_targets[0];
let pauli = after.get(key);
if (pauli === undefined || pauli === 'I') {
Expand All @@ -279,7 +284,7 @@ class Layer {
pauli = 'X';
}
after.set(key, pauli);
} else if (op.gate.name === 'MARKZ' && op.args[0] === marker_index) {
} else if (op.gate.name === MARKZ_NAME && op.args[0] === marker_index) {
let key = op.id_targets[0];
let pauli = after.get(key);
if (pauli === undefined || pauli === 'I') {
Expand Down Expand Up @@ -330,7 +335,7 @@ class Layer {
if (index !== undefined && op.args[0] !== index) {
return true;
}
if (op.gate.name !== 'MARKX' && op.gate.name !== 'MARKY' && op.gate.name !== 'MARKZ') {
if (!(MARKER_NAMES.includes(op.gate.name))) {
return true;
}
return op.id_targets[0] !== q;
Expand All @@ -343,7 +348,7 @@ class Layer {
*/
put(op, allow_overwrite=true) {
if (op.gate.is_marker) {
if (op.gate.name === 'MARKX' || op.gate.name === 'MARKY' || op.gate.name === 'MARKZ') {
if (MARKER_NAMES.includes(op.gate.name)) {
this.id_dropMarkersAt(op.id_targets[0], op.args[0]);
}
this.markers.push(op);
Expand Down
6 changes: 5 additions & 1 deletion glue/crumble/circuit/layer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ test("layer.put_get", () => {

let marker1 = new Operation(GATE_MAP.get("MARKX"), '', new Float32Array([0]), new Uint32Array([4]));
let marker2 = new Operation(GATE_MAP.get("MARKZ"), '', new Float32Array([1]), new Uint32Array([5]));
let marker3 = new Operation(GATE_MAP.get("REVMARKX"), '', new Float32Array([2]), new Uint32Array([4]));
let marker4 = new Operation(GATE_MAP.get("REVMARKZ"), '', new Float32Array([3]), new Uint32Array([5]));
layer.put(marker1);
layer.put(marker2);
layer.put(marker3);
layer.put(marker4);
assertThat(layer.id_ops).isEqualTo(new Map([
[2, op],
[3, op],
]));
assertThat(layer.markers).isEqualTo([marker1, marker2]);
assertThat(layer.markers).isEqualTo([marker1, marker2, marker3, marker4]);
});

test("layer.filtered", () => {
Expand Down
4 changes: 4 additions & 0 deletions glue/crumble/circuit/pauli_frame.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ test("pauli_frame.do_gate_vs_old_frame_updates", () => {
if (g.name === 'DETECTOR' || g.name === 'OBSERVABLE_INCLUDE') {
continue;
}
if (g.name.startsWith('REVMARK')) {
// skipping REVMARKs since they are not supported by legacy implementation
continue;
}
let before, after, returned;
if (g.num_qubits === 1) {
before = new PauliFrame(4, g.num_qubits);
Expand Down
12 changes: 8 additions & 4 deletions glue/crumble/circuit/propagated_pauli_frames.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,18 @@ class PropagatedPauliFrames {
* @param {!int} marker_index
* @returns {!PropagatedPauliFrames}
*/
static fromCircuit(circuit, marker_index) {
static fromCircuit(circuit, marker_index, reverse = false) {
let result = new PropagatedPauliFrames(new Map());

let bases = /** @type {!Map<!int, !string>} */ new Map();
for (let k = 0; k < circuit.layers.length; k++) {
const start = reverse ? circuit.layers.length - 1 : 0;
const end = reverse ? -1 : circuit.layers.length;
const step = reverse ? -1 : 1;

for (let k = start; reverse ? k > end : k < end; k += step) {
let layer = circuit.layers[k];
let prevBases = bases;
bases = layer.id_pauliFrameAfter(bases, marker_index);
bases = layer.id_pauliFrameAfter(bases, marker_index, reverse);

let errors = new Set();
for (let key of [...bases.keys()]) {
Expand Down Expand Up @@ -171,7 +175,7 @@ class PropagatedPauliFrames {
}

if (bases.size > 0) {
result.id_layers.set(k + 0.5, new PropagatedPauliFrameLayer(bases, new Set(), []));
result.id_layers.set(reverse ? k - 0.5 : k + 0.5, new PropagatedPauliFrameLayer(bases, new Set(), []));
}
if (errors.size > 0 || crossings.length > 0) {
result.id_layers.set(k, new PropagatedPauliFrameLayer(new Map(), errors, crossings));
Expand Down
2 changes: 1 addition & 1 deletion glue/crumble/crumble.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<br>
</div>
<div style="display: inline-block">
<canvas id="toolbox" style="width: 370px; height: 110px; border: 1px solid black; margin: 0; padding: 0;">
<canvas id="toolbox" style="width: 400px; height: 110px; border: 1px solid black; margin: 0; padding: 0;">
</canvas>
</div>
<div id='examples-div' style="border: 1px solid black; margin: 10px; display: none; width: fit-content">
Expand Down
14 changes: 12 additions & 2 deletions glue/crumble/draw/main_draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,16 @@ function draw(ctx, snap) {
let circuit = snap.circuit;

let numPropagatedLayers = 0;
let reversedMarkers = new Set();
for (let layer of circuit.layers) {
for (let op of layer.markers) {
let gate = op.gate;
if (gate.name === "MARKX" || gate.name === "MARKY" || gate.name === "MARKZ") {
numPropagatedLayers = Math.max(numPropagatedLayers, op.args[0] + 1);
}
if (gate.name === "REVMARKX" || gate.name === "REVMARKY" || gate.name === "REVMARKZ") {
reversedMarkers.add(op.args[0]);
}
}
}

Expand All @@ -217,8 +221,13 @@ function draw(ctx, snap) {
};
let propagatedMarkerLayers = /** @type {!Map<!int, !PropagatedPauliFrames>} */ new Map();
for (let mi = 0; mi < numPropagatedLayers; mi++) {
propagatedMarkerLayers.set(mi, PropagatedPauliFrames.fromCircuit(circuit, mi));
propagatedMarkerLayers.set(mi, PropagatedPauliFrames.fromCircuit(circuit, mi, false));
}
let propagatedRevMarkerLayers = /** @type {!Map<!int, !PropagatedPauliFrames>} */ new Map();
for (let mi of reversedMarkers) {
propagatedRevMarkerLayers.set(mi, PropagatedPauliFrames.fromCircuit(circuit, mi, true));
}

let {dets: dets, obs: obs} = circuit.collectDetectorsAndObservables(false);
let batch_input = [];
for (let mi = 0; mi < dets.length; mi++) {
Expand Down Expand Up @@ -349,6 +358,7 @@ function draw(ctx, snap) {
});

drawMarkers(ctx, snap, qubitDrawCoords, propagatedMarkerLayers);
drawMarkers(ctx, snap, qubitDrawCoords, propagatedRevMarkerLayers);

if (focusX !== undefined) {
ctx.save();
Expand Down Expand Up @@ -384,7 +394,7 @@ function draw(ctx, snap) {
});
});

drawTimeline(ctx, snap, propagatedMarkerLayers, qubitDrawCoords, circuit.layers.length);
drawTimeline(ctx, snap, propagatedMarkerLayers, qubitDrawCoords, circuit.layers.length, propagatedRevMarkerLayers);

// Draw scrubber.
ctx.save();
Expand Down
38 changes: 17 additions & 21 deletions glue/crumble/draw/timeline_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ let TIMELINE_PITCH = 32;
* @param {!int} max_t
* @param {!number} x_pitch
* @param {!Map} hitCounts
* @param {!boolean} reversed
*/
function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi, min_t, max_t, x_pitch, hitCounts) {
function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi, min_t, max_t, x_pitch, hitCounts, reversed) {
const colors = {'X': 'red', 'Y': 'green', 'Z': 'blue'};
const lightColors = {'X': '#ff7777', 'Y': '#77ff77', 'Z': '#7777ff'};

for (let t = min_t - 1; t <= max_t; t++) {
if (!hitCounts.has(t)) {
hitCounts.set(t, new Map());
Expand Down Expand Up @@ -45,16 +49,10 @@ function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi,
if (x === undefined || y === undefined) {
continue;
}
if (b === 'X') {
ctx.fillStyle = 'red'
} else if (b === 'Y') {
ctx.fillStyle = 'green'
} else if (b === 'Z') {
ctx.fillStyle = 'blue'
} else {
throw new Error('Not a pauli: ' + b);
}
ctx.fillStyle = reversed ? lightColors[b] : colors[b];
ctx.fillRect(x - dx, y - dy, wx, wy);
ctx.shadowColor = ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
ctx.filter = "none";
}
for (let q of p0.errors) {
let {dx, dy, wx, wy} = marker_placement(mi, q, hitCount);
Expand All @@ -74,15 +72,7 @@ function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi,
for (let {q1, q2, color} of p0.crossings) {
let [x1, y1] = qubitTimeCoordFunc(q1, t);
let [x2, y2] = qubitTimeCoordFunc(q2, t);
if (color === 'X') {
ctx.strokeStyle = 'red';
} else if (color === 'Y') {
ctx.strokeStyle = 'green';
} else if (color === 'Z') {
ctx.strokeStyle = 'blue';
} else {
ctx.strokeStyle = 'purple'
}
ctx.strokeStyle = reversed ? lightColors[color] : colors[color];
ctx.lineWidth = 8;
stroke_connector_to(ctx, x1, y1, x2, y2);
ctx.lineWidth = 1;
Expand All @@ -96,8 +86,9 @@ function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi,
* @param {!Map<!int, !PropagatedPauliFrames>} propagatedMarkerLayers
* @param {!function(!int): ![!number, !number]} timesliceQubitCoordsFunc
* @param {!int} numLayers
* @param {!Set<!int>} reversedMarkers
*/
function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFunc, numLayers) {
function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFunc, numLayers, propagatedRevMarkerLayers = new Map()) {
let w = Math.floor(ctx.canvas.width / 2);

let qubits = snap.timelineQubits();
Expand Down Expand Up @@ -161,10 +152,15 @@ function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFun

// Draw colored indicators showing Pauli propagation.
let hitCounts = new Map();
for (let [mi, p] of propagatedRevMarkerLayers.entries()) {
drawTimelineMarkers(ctx, snap, qubitTimeCoords, p, mi, min_t_clamp, max_t, x_pitch, hitCounts, true);
}

for (let [mi, p] of propagatedMarkerLayers.entries()) {
drawTimelineMarkers(ctx, snap, qubitTimeCoords, p, mi, min_t_clamp, max_t, x_pitch, hitCounts);
drawTimelineMarkers(ctx, snap, qubitTimeCoords, p, mi, min_t_clamp, max_t, x_pitch, hitCounts, false);
}


// Draw highlight of current layer.
ctx.globalAlpha *= 0.5;
ctx.fillStyle = 'black';
Expand Down
2 changes: 1 addition & 1 deletion glue/crumble/editor/editor_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class EditorState {
clearMarkers() {
let c = this.copyOfCurCircuit();
for (let layer of c.layers) {
layer.markers = layer.markers.filter(e => e.gate.name !== 'MARKX' && e.gate.name !== 'MARKY' && e.gate.name !== 'MARKZ');
layer.markers = layer.markers.filter(e => !e.gate.name.endsWith('MARKX') && !e.gate.name.endsWith('MARKY') && !e.gate.name.endsWith('MARKZ'));
}
this.commit(c);
}
Expand Down
3 changes: 3 additions & 0 deletions glue/crumble/gates/gateset.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ test("gateset.expected_gates", () => {
expectedGates.add("MARKY");
expectedGates.add("MARKZ");
expectedGates.add("MARK");
expectedGates.add("REVMARKX");
expectedGates.add("REVMARKY");
expectedGates.add("REVMARKZ");
expectedGates.add("RZ");
expectedGates.add("MZ");
expectedGates.add("MRZ");
Expand Down
30 changes: 30 additions & 0 deletions glue/crumble/gates/gateset_markers.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,36 @@ function *iter_gates_markers() {
ctx.fillRect(x1 - rad, y1 - rad, rad, rad);
}
);
yield new Gate(
'REVMARKX',
1,
true,
true,
undefined,
() => {},
() => {},
make_marker_drawer('#ff7777'),
);
yield new Gate(
'REVMARKY',
1,
true,
true,
undefined,
() => {},
() => {},
make_marker_drawer('#77ff77'),
);
yield new Gate(
'REVMARKZ',
1,
true,
true,
undefined,
() => {},
() => {},
make_marker_drawer('#7777ff'),
);
}

export {iter_gates_markers, marker_placement};
28 changes: 21 additions & 7 deletions glue/crumble/keyboard/toolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ let DIAM = 28;
let PITCH = DIAM + 4;
let PAD = 10.5;

let COLUMNS = ['H', 'S', 'R', 'M', 'MR', 'C', 'W', 'SC', 'MC', 'P', '1-9'];
let COLUMNS = ['H', 'S', 'R', 'M', 'MR', 'C', 'W', 'SC', 'MC', 'P', '1-9', '⇧1-9'];
let DEF_ROW = [1, 2, 2, 2, 2, 1, 2, 2, 2, -1, -1, -1];

let COLORMAP = { 'X1': 'red', 'Y1': 'green', 'Z1': 'blue', 'X1N': '#ff7777', 'Y1N': '#77ff77', 'Z1N': '#7777ff' };

/**
* @param {!ChordEvent} ev
* @returns {undefined|!{row: !int, strength: !number}}
Expand Down Expand Up @@ -92,6 +94,13 @@ function make_pos_to_gate_dict() {
result.set(`${x},-1`, GATE_MAP.get("MARK").withDefaultArgument(k));
x += 1;
}
// Add entries for the '⇧1-9' column (column 11)
for (let k = 0; k < 4; k++) {
result.set(`${x},0`, GATE_MAP.get("REVMARKX").withDefaultArgument(k));
result.set(`${x},1`, GATE_MAP.get("REVMARKY").withDefaultArgument(k));
result.set(`${x},2`, GATE_MAP.get("REVMARKZ").withDefaultArgument(k));
x += 1;
}
return result;
}
let POS_TO_GATE_DICT = make_pos_to_gate_dict();
Expand Down Expand Up @@ -145,9 +154,9 @@ function drawToolbox(ev) {

ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
let xGates = ['H_YZ', 'S_X', 'R_X', 'M_X', 'MR_X', 'C_X', 'CXSWAP', '√XX', 'M_XX', 'PX', 'X1'];
let yGates = ['H', 'S_Y', 'R_Y', 'M_Y', 'MR_Y', 'C_Y', 'SWAP', '√YY', 'M_YY', 'PY', 'Y1'];
let zGates = ['H_XY', 'S', 'R', 'M', 'MR', 'C_Z', 'CZSWAP', '√ZZ', 'M_ZZ', 'PZ', 'Z1'];
let xGates = ['H_YZ', 'S_X', 'R_X', 'M_X', 'MR_X', 'C_X', 'CXSWAP', '√XX', 'M_XX', 'PX', 'X1', 'X1N'];
let yGates = ['H', 'S_Y', 'R_Y', 'M_Y', 'MR_Y', 'C_Y', 'SWAP', '√YY', 'M_YY', 'PY', 'Y1', 'Y1N'];
let zGates = ['H_XY', 'S', 'R', 'M', 'MR', 'C_Z', 'CZSWAP', '√ZZ', 'M_ZZ', 'PZ', 'Z1', 'Z1N'];
let gates = [xGates, yGates, zGates];
for (let k = 0; k < COLUMNS.length; k++) {
for (let p = 0; p < 3; p++) {
Expand Down Expand Up @@ -193,20 +202,25 @@ function drawToolbox(ev) {
ctx.globalAlpha *= 4;
continue;
}
if (text.endsWith('1')) {
if (text.endsWith('1') || text.endsWith('1N')) {
ctx.beginPath();
ctx.moveTo(cx + PITCH * 0.15, cy - PITCH * 0.25);
ctx.lineTo(cx, cy + PITCH * 0.1);
ctx.lineTo(cx - PITCH * 0.15, cy - PITCH * 0.25);
ctx.closePath();
let color = text === 'X1' ? 'red' : text === 'Y1' ? 'green' : 'blue';
let color = COLORMAP[text] || 'black';
ctx.fillStyle = color;
ctx.strokeStyle = color;
ctx.fill();
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(cx + DIAM * 0.5, cy);
if (text.endsWith('1N')) {
// Draw a negated arrow (arrow pointing left instead of right)
ctx.lineTo(cx - DIAM * 0.5, cy);
} else {
ctx.lineTo(cx + DIAM * 0.5, cy);
}
ctx.stroke();
ctx.lineWidth = 1;
continue;
Expand Down
Loading