Skip to content

Commit

Permalink
[WIP] Add UX for creating detectors in crumble
Browse files Browse the repository at this point in the history
  • Loading branch information
Strilanc committed May 24, 2024
1 parent 9c97029 commit 4146f9d
Show file tree
Hide file tree
Showing 31 changed files with 706 additions and 98 deletions.
4 changes: 2 additions & 2 deletions glue/crumble/base/revision.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ class Revision {
* the previous state.
* @returns {void}
*/
startedWorkingOnCommit() {
this.isWorkingOnCommit = true;
startedWorkingOnCommit(newCheckpoint) {
this.isWorkingOnCommit = newCheckpoint !== this.history[this.index];
this._changes.send(undefined);
}

Expand Down
149 changes: 136 additions & 13 deletions glue/crumble/circuit/circuit.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class Circuit {
replaceAll(' DAG ', '_DAG ').
replaceAll('C ZYX', 'C_ZYX').split('\n');
let layers = [new Layer()];
let num_detectors = 0;
let i2q = new Map();
let used_positions = new Set();

Expand Down Expand Up @@ -233,6 +234,7 @@ class Circuit {
}
};

let measurement_locs = [];
let processLine = line => {
let args = [];
let targets = [];
Expand All @@ -257,6 +259,9 @@ class Circuit {
if (name === '') {
return;
}
if (args.length > 0 && ['M', 'MX', 'MY', 'MZ', 'MR', 'MRX', 'MRY', 'MRZ', 'MPP', 'MPAD'].indexOf(name) !== -1) {
args = [];
}
let alias = GATE_ALIAS_MAP.get(name);
if (alias !== undefined) {
if (alias.ignore) {
Expand All @@ -274,14 +279,36 @@ class Circuit {
let combinedTargets = splitUncombinedTargets(targets);
let layer = layers[layers.length - 1]
for (let combo of combinedTargets) {
let op = simplifiedMPP(new Float32Array(args), combo);
try {
layer.put(simplifiedMPP(new Float32Array(args), combo), false);
layer.put(op, false);
} catch (_) {
layers.push(new Layer());
layer = layers[layers.length - 1];
layer.put(simplifiedMPP(new Float32Array(args), combo), false);
layer.put(op, false);
}
measurement_locs.push({layer: layers.length - 1, targets: op.id_targets});
}
return;
} else if (name === 'DETECTOR') {
for (let target of targets) {
if (!target.startsWith("rec[-") || ! target.endsWith("]")) {
console.warn("Ignoring bad detector " + line);
return;
}
let index = measurement_locs.length + Number.parseInt(target.substring(4, target.length - 1));
if (index < 0 || index >= measurement_locs.length) {
console.warn("Ignoring bad detector " + line);
return;
}
let loc = measurement_locs[index];
layers[loc.layer].markers.push(
new Operation(GATE_MAP.get('DETECTOR'),
new Float32Array([num_detectors]),
new Uint32Array([loc.targets[0]]),
));
}
num_detectors += 1;
return;
} else if (name === 'SPP' || name === 'SPP_DAG') {
let dag = name === 'SPP_DAG';
Expand Down Expand Up @@ -314,26 +341,35 @@ class Circuit {
return;
}

let ignored = false;
let has_feedback = false;
for (let targ of targets) {
if (targ.startsWith("rec[")) {
if (name === "CX" || name === "CY" || name === "CZ" || name === "ZCX" || name === "ZCY") {
ignored = true;
break;
has_feedback = true;
}
}
if (typeof parseInt(targ) !== 'number') {
} else if (typeof parseInt(targ) !== 'number') {
throw new Error(line);
}
}
if (ignored) {
console.warn("IGNORED", name);
return;
if (has_feedback) {
let clean_targets = [];
for (let k = 0; k < targets.length; k += 2) {
if (targets[k].startsWith("rec[") || targets[k + 1].startsWith("rec[")) {
console.warn("IGNORED", name, targets[k], targets[k + 1]);
} else {
clean_targets.push(targets[k]);
clean_targets.push(targets[k + 1]);
}
}
targets = clean_targets;
if (targets.length === 0) {
return;
}
}

let gate = GATE_MAP.get(name);
if (gate === undefined) {
console.warn("Unrecognized gate name in " + line);
console.warn("Ignoring unrecognized instruction: " + line);
return;
}
let a = new Float32Array(args);
Expand All @@ -351,12 +387,16 @@ class Circuit {
sub_targets.reverse();
}
let qs = new Uint32Array(sub_targets);
let op = new Operation(gate, a, qs);
try {
layer.put(new Operation(gate, a, qs), false);
layer.put(op, false);
} catch (_) {
layers.push(new Layer());
layer = layers[layers.length - 1];
layer.put(new Operation(gate, a, qs), false);
layer.put(op, false);
}
if (op.countMeasurements() > 0) {
measurement_locs.push({layer: layers.length - 1, targets: op.id_targets});
}
}
}
Expand Down Expand Up @@ -506,6 +546,53 @@ class Circuit {
return new Circuit(newCoords, newLayers);
}

/**
* @returns {!Array.<!Array.<!int>>}
*/
collectDetectors() {
let detectors = [];
let m2d = new Map();
for (let k = 0; k < this.layers.length; k++) {
let layer = this.layers[k];
for (let [target_id, op] of layer.id_ops.entries()) {
if (op.id_targets[0] === target_id) {
if (op.countMeasurements() > 0) {
m2d.set(`${k}:${target_id}`, m2d.size);
}
}
}
}
for (let k = 0; k < this.layers.length; k++) {
let layer = this.layers[k];
for (let op of layer.markers) {
if (op.gate.name === 'DETECTOR') {
let d = Math.round(op.args[0]);
while (detectors.length <= d) {
detectors.push([]);
}
let key = `${k}:${op.id_targets[0]}`;
if (m2d.has(key)) {
detectors[d].push(m2d.get(key) - m2d.size);
}
}
}
}
let seen = new Set();
let keptDetectors = [];
for (let ds of detectors) {
if (ds.length > 0) {
ds.sort((a, b) => b - a);
let key = ds.join(':');
if (!seen.has(key)) {
seen.add(key);
keptDetectors.push(ds);
}
}
}
keptDetectors.sort((a, b) => a[0] - b[0]);
return keptDetectors;
}

/**
* @returns {!string}
*/
Expand All @@ -519,6 +606,11 @@ class Circuit {
}
}

let remainingDetectors = this.collectDetectors();
remainingDetectors.reverse();
let seenMeasurements = 0;
let totalMeasurements = this.countMeasurements();

let packedQubitCoords = [];
for (let q of usedQubits) {
let x = this.qubitCoordData[2*q];
Expand Down Expand Up @@ -574,11 +666,15 @@ class Circuit {
let targetGroups = [];

let gateName = nameWithArgs.split('(')[0];
if (gateName === 'DETECTOR') {
continue;
}

let gate = GATE_MAP.get(gateName);
if (gate === undefined && (gateName === 'MPP' || gateName === 'SPP' || gateName === 'SPP_DAG')) {
let line = [gateName + ' '];
for (let op of group) {
seenMeasurements += op.countMeasurements();
let bases = op.gate.name.substring(gateName.length + 1);
for (let k = 0; k < op.id_targets.length; k++) {
line.push(bases[k] + old2new.get(op.id_targets[k]));
Expand All @@ -592,11 +688,13 @@ class Circuit {
if (gate !== undefined && gate.can_fuse) {
let flatTargetGroups = [];
for (let op of group) {
seenMeasurements += op.countMeasurements();
flatTargetGroups.push(...op.id_targets)
}
targetGroups.push(flatTargetGroups);
} else {
for (let op of group) {
seenMeasurements += op.countMeasurements();
targetGroups.push([...op.id_targets])
}
}
Expand All @@ -610,6 +708,20 @@ class Circuit {
}
}
}
while (remainingDetectors.length > 0) {
let candidate = remainingDetectors[remainingDetectors.length - 1];
let offset = totalMeasurements - seenMeasurements;
if (candidate[0] + offset >= 0) {
break;
}
remainingDetectors.pop();
let line = ['DETECTOR'];
for (let d of candidate) {
line.push(`rec[${d + offset}]`)
}
out.push(line.join(' '));
}

out.push(`TICK`);
}
while (out.length > 0 && out[out.length - 1] === 'TICK') {
Expand All @@ -619,6 +731,17 @@ class Circuit {
return out.join('\n');
}

/**
* @returns {!int}
*/
countMeasurements() {
let total = 0;
for (let layer of this.layers) {
total += layer.countMeasurements();
}
return total;
}

/**
* @param {!Iterable<![!number, !number]>} coords
*/
Expand Down
28 changes: 28 additions & 0 deletions glue/crumble/circuit/circuit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ S 1 2
`.trim());
});

test("circuit.fromStimCircuit_strip_measurement_noise", () => {
let c1 = Circuit.fromStimCircuit(`
M(0.1) 0
`);
assertThat(c1.toStimCircuit()).isEqualTo(`
QUBIT_COORDS(0, 0) 0
M 0
`.trim());
});

test("circuit.fromStimCircuit_detector", () => {
let c = Circuit.fromStimCircuit(`
R 0
M 0
DETECTOR rec[-1]
R 0
`);
assertThat(c.toStimCircuit()).isEqualTo(`
QUBIT_COORDS(0, 0) 0
R 0
TICK
M 0
TICK
R 0
DETECTOR rec[-1]
`.trim());
})

test("circuit.fromStimCircuit_mpp", () => {
let c1 = Circuit.fromStimCircuit(`
QUBIT_COORDS(1, 2) 0
Expand Down
13 changes: 13 additions & 0 deletions glue/crumble/circuit/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ class Layer {
return result;
}

/**
* @returns {!int}
*/
countMeasurements() {
let total = 0;
for (let [target_id, op] of this.id_ops.entries()) {
if (op.id_targets[0] === target_id) {
total += op.countMeasurements();
}
}
return total;
}

/**
* @return {!boolean}
*/
Expand Down
16 changes: 16 additions & 0 deletions glue/crumble/circuit/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ class Operation {
this.id_targets = targets;
}

/**
* @returns {!int}
*/
countMeasurements() {
if (this.gate.name === 'M' || this.gate.name === 'MX' || this.gate.name === 'MY' || this.gate.name === 'MR' || this.gate.name === 'MRX' || this.gate.name === 'MRY') {
return this.id_targets.length;
}
if (this.gate.name === 'MXX' || this.gate.name === 'MYY' || this.gate.name === 'MZZ') {
return this.id_targets.length / 2;
}
if (this.gate.name.startsWith('MPP:')) {
return 1;
}
return 0;
}

/**
* @param {!string} before
* @returns {!string}
Expand Down
Loading

0 comments on commit 4146f9d

Please sign in to comment.