-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
3D circuit visualization using Typescript dev environment (#4334)
### 3D circuit visualization This PR implements the features discussed in the [3D Quantum Circuits RFC](https://docs.google.com/document/d/1dLKj8oAF_JhDWU4zLU7XMz3aBXymd0hk_9n6U0mEtms/edit?usp=sharing). #### Relevant Issues and PRs #1075 - 3D diagrams for circuits #4171 - Typescript development in Cirq and prototype bloch sphere implementation #### Features implemented - All features of a [Cirq Typescript widget](#4171) - End to end display of circuits - Serialization of cirq.Circuit objects, re-representation in Typescript - Support for arbitrary length gates - Testing for the different components - A short jupyter notebook example https://user-images.githubusercontent.com/17647506/126213608-0c2d09d1-d5c2-4fa0-a8ae-3f0780f09912.mp4
- Loading branch information
1 parent
10c78c9
commit 0d4a31b
Showing
28 changed files
with
1,905 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"id": "737bce11", | ||
"metadata": {}, | ||
"source": [ | ||
"#### Copyright 2021 The Cirq Developers" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "6db8c987", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", | ||
"# you may not use this file except in compliance with the License.\n", | ||
"# You may obtain a copy of the License at\n", | ||
"#\n", | ||
"# https://www.apache.org/licenses/LICENSE-2.0\n", | ||
"#\n", | ||
"# Unless required by applicable law or agreed to in writing, software\n", | ||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n", | ||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", | ||
"# See the License for the specific language governing permissions and\n", | ||
"# limitations under the License." | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "88f3b242", | ||
"metadata": {}, | ||
"source": [ | ||
"### Cirq-web 3D circuit visualization" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "9f4089af", | ||
"metadata": {}, | ||
"source": [ | ||
"\n", | ||
"<table class=\"tfo-notebook-buttons\" align=\"left\">\n", | ||
" <td>\n", | ||
" <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/master/master/cirq-web/circuit-example.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n", | ||
" </td>\n", | ||
" <td>\n", | ||
" <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/master/cirq-web/circuit-example.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n", | ||
" </td>\n", | ||
"</table>" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "99172e40", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"!pip install --quiet cirq --pre" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "ebc22e4d", | ||
"metadata": {}, | ||
"source": [ | ||
"Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "e4bd9946", | ||
"metadata": { | ||
"scrolled": true | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"!pip install cirq-web" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "fe0d0e69", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import cirq\n", | ||
"qubits = [cirq.GridQubit(x, y) for x in range(10) for y in range(10)]\n", | ||
"\n", | ||
"import cirq.testing\n", | ||
"from cirq.protocols import circuit_diagram_info\n", | ||
"circuit = cirq.testing.random_circuit(cirq.GridQubit.square(10), n_moments=5, op_density=.7)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "81689b3f", | ||
"metadata": { | ||
"scrolled": false | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"\"\"\"\n", | ||
"This cell builds a 3D circuit diagram using a big list of operations provided TS Circuit class.\n", | ||
"\"\"\"\n", | ||
"import cirq_web\n", | ||
"from typing import Optional\n", | ||
"from cirq_web.circuits.symbols import SymbolInfo\n", | ||
"\n", | ||
"class FunkyHadamard(cirq_web.circuits.symbols.SymbolResolver):\n", | ||
" def resolve(self, operation: cirq.Operation) -> Optional[SymbolInfo]:\n", | ||
" if isinstance(operation.gate, cirq.HPowGate):\n", | ||
" return SymbolInfo(['Hello!'], ['yellow'])\n", | ||
" else:\n", | ||
" return None\n", | ||
" \n", | ||
"resolvers = list(cirq_web.circuits.symbols.DEFAULT_SYMBOL_RESOLVERS) + [\n", | ||
" FunkyHadamard()\n", | ||
"]\n", | ||
"\n", | ||
"from cirq_web import Circuit3D\n", | ||
"c3d = Circuit3D(circuit, resolvers, 2.5)\n", | ||
"display(c3d)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "139acc3d", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.7.3" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/** | ||
* @license | ||
* Copyright 2010-2021 Three.js Authors | ||
* SPDX-License-Identifier: MIT | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<title>Cirq Web Development page</title> | ||
</head> | ||
<body> | ||
<div id="container"></div> | ||
<script src="/bloch_sphere.bundle.js"></script> | ||
<script> | ||
renderBlochSphere('container', 5) | ||
.addVector(1, 0, 0); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<html lang="en"> | ||
<head> | ||
<title>Cirq Web Development Page -- 3D circuits</title> | ||
</head> | ||
<body> | ||
<button id="camera-reset">Reset Camera</button> | ||
<button id="camera-toggle">Toggle Camera Type</button> | ||
<div id="mycircuitdiv"></div> | ||
<script src="/circuit.bundle.js"></script> | ||
<script> | ||
const circuit = createGridCircuit( | ||
[ | ||
{'wire_symbols': ['Z'], 'location_info': [{'row': 2, 'col': 3}], 'color_info': ['cyan'], 'moment': 0}, | ||
{'wire_symbols': ['X'], 'location_info': [{'row': 2, 'col': 3}], 'color_info': ['black'], 'moment': 1}, | ||
{'wire_symbols': ['@', 'X'], 'location_info': [{'row': 3, 'col': 0}, {'row': 0, 'col': 0}], 'color_info': ['black', 'black'], 'moment': 0}, | ||
], 5, 'mycircuitdiv', 1); | ||
|
||
// Event listener for reset press | ||
document.getElementById("camera-reset").addEventListener('click', () => { | ||
circuit.scene.setCameraAndControls(circuit.circuit); | ||
}); | ||
|
||
// Event listener for camera change | ||
document.getElementById("camera-toggle").addEventListener('click', () => { | ||
circuit.scene.toggleCamera(circuit.circuit); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright 2021 The Cirq Developers | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import puppeteer from 'puppeteer'; | ||
import {expect} from 'chai'; | ||
import {readFileSync} from 'fs'; | ||
import pixelmatch from 'pixelmatch'; | ||
import * as PNG from 'pngjs'; | ||
import * as temp from 'temp'; | ||
import * as path from 'path'; | ||
|
||
/** | ||
* Generates an HTML script with the current repository bundle | ||
* that we will use to compare. | ||
*/ | ||
|
||
// Due to the path, reading the file will only work by running this file in the same directory | ||
// as the package.json file. | ||
const bundleString = readFileSync('dist/circuit.bundle.js'); | ||
function htmlContent(clientCode: string) { | ||
return ` | ||
<!doctype html> | ||
<meta charset="UTF-8"> | ||
<html lang="en"> | ||
<head> | ||
<title>Cirq Web Development page</title> | ||
</head> | ||
<body> | ||
<div id="mycircuitdiv"></div> | ||
<script>${bundleString}</script> | ||
<script>${clientCode}</script> | ||
</body> | ||
</html> | ||
`; | ||
} | ||
|
||
// Automatically track and cleanup files on exit | ||
temp.track(); | ||
|
||
describe('Circuit', () => { | ||
temp.mkdir('tmp', (err, dirPath) => { | ||
const outputPath = path.join(dirPath, 'circuit.png'); | ||
|
||
before(async () => { | ||
const browser = await puppeteer.launch({args: ['--app']}); | ||
const page = await browser.newPage(); | ||
|
||
// Take a screenshot of the first image | ||
await page.setContent( | ||
htmlContent(` | ||
const circuit = createGridCircuit( | ||
[ | ||
{ | ||
'wire_symbols': ['Z'], | ||
'location_info': [{'row': 2, 'col': 3}], | ||
'color_info': ['cyan'], | ||
'moment': 0 | ||
}, | ||
{ | ||
'wire_symbols': ['X'], | ||
'location_info': [{'row': 2, 'col': 3}], | ||
'color_info': ['black'], | ||
'moment': 1 | ||
}, | ||
{ | ||
'wire_symbols': ['@', 'X'], | ||
'location_info': [{'row': 3, 'col': 0}, {'row': 0, 'col': 0}], | ||
'color_info': ['black', 'black'], | ||
'moment': 0 | ||
}, | ||
], 5, 'mycircuitdiv' | ||
); | ||
`) | ||
); | ||
await page.screenshot({path: outputPath}); | ||
await browser.close(); | ||
}); | ||
|
||
it('with limited gates matches the gold copy', () => { | ||
const expected = PNG.PNG.sync.read( | ||
readFileSync('e2e/circuit/circuit_expected.png') | ||
); | ||
const actual = PNG.PNG.sync.read(readFileSync(outputPath)); | ||
const {width, height} = expected; | ||
const diff = new PNG.PNG({width, height}); | ||
|
||
const pixels = pixelmatch( | ||
expected.data, | ||
actual.data, | ||
diff.data, | ||
width, | ||
height, | ||
{threshold: 0.1} | ||
); | ||
|
||
expect(pixels).to.equal(0); | ||
}); | ||
}); | ||
}); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.