Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
amirebrahimi committed Jan 23, 2021
2 parents ce92578 + 977d606 commit df51df8
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 3 deletions.
15 changes: 12 additions & 3 deletions html/export.partial.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,23 @@
<pre tabindex="104" id="export-circuit-json-pre" style="overflow:auto; max-width:600px; max-height:60px; border: 1px solid black; padding:5px; margin:2px;"></pre>
</div>

<br>
<strong>OpenQASM</strong>
<div style="margin: 10px 0 0 20px;">
<button tabindex="105" id="export-qasm-copy-button">Copy to Clipboard</button>&nbsp;&nbsp;<span id="export-qasm-copy-result"></span>
<br>
<pre tabindex="106" id="export-qasm-pre" style="overflow:auto; max-width:600px; max-height:200px; border: 1px solid black; padding:5px; margin:2px;"></pre>
</div>


<br>
<strong>Simulation Data JSON</strong> - Output amplitudes, detector results, display data, etc.
<div style="margin: 10px 0 0 20px;">
<button tabindex="105" id="export-amplitudes-button">Generate and Copy to Clipboard</button>&nbsp;<span id="export-amplitudes-result"></span>
<input type="checkbox" tabindex="106" id="export-amplitudes-use-amps" style="float: right; margin-right: 10px;">
<button tabindex="107" id="export-amplitudes-button">Generate and Copy to Clipboard</button>&nbsp;<span id="export-amplitudes-result"></span>
<input type="checkbox" tabindex="108" id="export-amplitudes-use-amps" style="float: right; margin-right: 10px;">
<label style="float: right" for="export-amplitudes-use-amps">Skip output amplitudes</label>
<br>
<pre tabindex="107" id="export-amplitudes-pre" style="overflow:auto; max-width:600px; max-height:60px; border: 1px solid black; padding:5px; margin:2px;"></pre>
<pre tabindex="109" id="export-amplitudes-pre" style="overflow:auto; max-width:600px; max-height:60px; border: 1px solid black; padding:5px; margin:2px;"></pre>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
},
"scripts": {
"build": "grunt build-src",
"build-debug": "grunt build-debug && cp ./out/quirk.html /mnt/x -f",
"test": "grunt test",
"test-chrome": "grunt test-chrome",
"test-firefox": "grunt test-firefox",
Expand Down
154 changes: 154 additions & 0 deletions src/ui/exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,141 @@ function initExports(revision, mostRecentStats, obsIsAnyOverlayShowing) {
}, 1000);
});

const convertJsonToQasm = (jsonText) => {
// X, Y, Z, H, S, T, Sdg, Tdg, Swap, CX, CCX, RX, RY, RZ, SX, SXdg, Measure, CRX, CRY, CRZ
const map = {
X: "x",
Y: "y",
Z: "z",
H: "h",
"Z^½": "s",
"Z^¼": "t",
"Z^-½": "sdg",
"Z^-¼": "tdg",
"Swap": "swap",
"•": "c",
"Rxft": "rx",
"Ryft": "ry",
"Rzft": "rz",
"X^½": "sx",
"X^-½": "sxdg",
"Measure": "measure"
}
let qasmString = 'OPENQASM 2.0;include "qelib1.inc";';//here
//noinspection UnusedCatchParameterJS
var json = ""

const handleControlGates = (arr) => {
var qasmStr = "";
const controlGate = "•";
const acceptedGates = {
1: ['H', 'X', 'Y', 'Z', 'Rxft', 'Ryft', 'Rzft', 'X^½', 'Swap'],
2: ['X']
}
// the way quirk works, if you have a control in any column, all gates in the column are controlled
var numCtrls = arr.filter(elem => elem == controlGate).length;
if (numCtrls > 2) throw new Error("Too many controls (max 2)");

//check for unsupported gates
// if (arr.filter(elem => !acceptedGates[numCtrls].includes(elem) && elem != 1 && elem != controlGate).length !== 0) {
// // check for invalid control ops
// //TODO - better logging?
// throw new Error("Invalid circuit - some controlled operations are not supported!");
// }

//check for at least 1 supported gate
if (arr.filter(elem => elem !== controlGate && elem !== 1).length === 0) {
throw new Error("Invalid circuit - controlled operation not specified!")
}


const ctrlString = "c".repeat(numCtrls);
const ctrlQubits = ` q[${arr.indexOf("•")}],` + (numCtrls == 2 ? `q[${arr.lastIndexOf("•")}],` : ``);

arr.forEach((gate, idx) => {
if (gate == controlGate || gate == 1) return;
//if (!acceptedGates[numCtrls].includes(gate)) throw new Error(`Unsupported control gate (${ctrlString+map[gate]})`)
if (typeof gate == "string") {
if (!acceptedGates[numCtrls].includes(gate)) throw new Error(`Unsupported control gate (${ctrlString+gate})`)
var targetQubits;
if (gate == "Swap") {
if (arr.filter(elem => elem == 'Swap').length != 2) throw new Error('Wrong number of swaps!');
targetQubits = `q[${arr.indexOf('Swap')}],q[${arr.lastIndexOf('Swap')}];`;//here
arr[arr.lastIndexOf('Swap')] = arr[arr.indexOf('Swap')] = 1;
}
else targetQubits = `q[${idx}];`;//here
qasmStr = qasmStr + ctrlString + map[gate] + ctrlQubits + targetQubits;
//console.log(qasmStr);
}
else { //parametrized gate
if(!acceptedGates[numCtrls].includes(gate["id"])) throw new Error(`Unsupported control gate (${ctrlString+gate["id"]})`)
qasmStr = qasmStr + ctrlString + `${map[gate["id"]]}(${gate["arg"]})${ctrlQubits}q[${idx}];`;//here
//console.log(qasmStr);
}

});
return qasmStr;

}


try {
json = JSON.parse(jsonText)
const cols = json["cols"];
if (cols.length === 0) return "Empty circuit";
const numQubits = Math.max(...(cols.map((arr) => arr.length)));
const numCbits = cols.filter(arr => arr.includes("Measure")).length;

qasmString += `qreg q[${numQubits}];`;//here
if (numCbits > 0) qasmString +=`creg c[${numCbits}];`;//here

var measurements = 0;

cols.forEach((col) => {
//var measureStr = "";
if (col.includes('Rxft') || col.includes('Ryft') || col.includes('Rzft'))
throw new Error("R*ft gates not supported, please provide a time-independent parameter")

// if col contains controls, parse it fully and move on
if (col.includes("•")) {
qasmString += handleControlGates(col);
return;
}


// no controls left!
col.forEach((gate, idx) => {
if (gate == 1) return;
if (typeof gate == "string") {
if (!Object.keys(map).includes(gate)) throw new Error("Unsupported gate!");
if (gate == "Measure") {
qasmString += `measure q[${idx}]->c[${measurements}];`;//here
measurements = measurements + 1;
return;
}
if (gate == "Swap") {
if (col.filter(elem => elem == 'Swap').length != 2) throw new Error('Wrong number of swaps!');
var targetQubits = ` q[${col.indexOf('Swap')}],q[${col.lastIndexOf('Swap')}];`;//here
col[col.lastIndexOf('Swap')] = col[col.indexOf('Swap')] = 1;
qasmString += map[gate] + targetQubits;
return;
}
qasmString += map[gate] + ` q[${idx}];`;//here
}
else if(typeof gate == "object") {
if (!Object.keys(map).includes(gate["id"])) throw new Error("Unsupported gate!");
qasmString += `${map[gate["id"]]}(${gate["arg"]}) q[${idx}];`;//here
}
});
});
}
catch(e) {
console.error(e)
return "Invalid Circuit JSON."
}
return qasmString;
}

// Export escaped link.
(() => {
const linkElement = /** @type {HTMLAnchorElement} */ document.getElementById('export-escaped-anchor');
Expand Down Expand Up @@ -107,6 +242,25 @@ function initExports(revision, mostRecentStats, obsIsAnyOverlayShowing) {
});
})();

// Export QASM
(() => {
const qasmTextElement = /** @type {HTMLPreElement} */ document.getElementById('export-qasm-pre');
const copyButton = /** @type {HTMLButtonElement} */ document.getElementById('export-qasm-copy-button');
const copyResultElement = /** @type {HTMLElement} */ document.getElementById('export-qasm-copy-result');
setupButtonElementCopyToClipboard(copyButton, qasmTextElement, copyResultElement);
revision.latestActiveCommit().subscribe(jsonText => {
//noinspection UnusedCatchParameterJS
//debugger;
try {
let val = convertJsonToQasm(jsonText);
qasmTextElement.innerText = val;
} catch (_) {
console.error("ERROR")
qasmTextElement.innerText = jsonText;
}
});
})();

// Export final output.
(() => {
const outputTextElement = /** @type {HTMLPreElement} */ document.getElementById('export-amplitudes-pre');
Expand Down

0 comments on commit df51df8

Please sign in to comment.