├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── GruntFile.js ├── LICENSE ├── PuppeteerRunTests.js ├── PuppeteerScreenshotCircuit.js ├── README.md ├── doc ├── MANUAL_amp-display.png ├── MANUAL_bloch-display.png ├── MANUAL_chance-display.png ├── MANUAL_circuit-editing-area.png ├── MANUAL_controlled-display.png ├── MANUAL_controlled-epr-display.png ├── MANUAL_density-display.png ├── MANUAL_measurement-types.png ├── MANUAL_menu.png ├── MANUAL_state-channel-duality.png ├── MANUAL_various-displays.png ├── README.md ├── README_Demo.gif ├── README_Grover.gif ├── README_Teleportation.gif └── favicon.ico ├── html ├── error.partial.html ├── export.partial.html ├── forge.partial.html ├── menu.partial.html └── quirk.template.html ├── karma.test.conf.js ├── karma.test_perf.conf.js ├── package-lock.json ├── package.json ├── src ├── Config.js ├── base │ ├── CooldownThrottle.js │ ├── Describe.js │ ├── DetailedError.js │ ├── Equate.js │ ├── Format.js │ ├── Obs.js │ ├── RestartableRng.js │ ├── Revision.js │ ├── Seq.js │ └── Util.js ├── browser │ ├── Clipboard.js │ ├── EventUtil.js │ ├── HistoryPusher.js │ ├── MouseWatcher.js │ ├── Polyfills.js │ ├── SaveFile.js │ └── TouchScrollBlocker.js ├── circuit │ ├── CircuitComputeUtil.js │ ├── CircuitDefinition.js │ ├── CircuitEvalContext.js │ ├── CircuitShaders.js │ ├── CircuitStats.js │ ├── Controls.js │ ├── CustomGateSet.js │ ├── Gate.js │ ├── GateCheckArgs.js │ ├── GateColumn.js │ ├── GateShaders.js │ ├── KetShaderUtil.js │ ├── KetTextureUtil.js │ └── Serializer.js ├── draw │ ├── CachablePainting.js │ ├── GateDrawParams.js │ ├── GatePainting.js │ ├── MathPainter.js │ ├── Painter.js │ └── WidgetPainter.js ├── fallback.js ├── gates │ ├── AllGates.js │ ├── AmplitudeDisplay.js │ ├── ArithmeticGates.js │ ├── BitCountGates.js │ ├── BlochSphereDisplay.js │ ├── ComparisonGates.js │ ├── Controls.js │ ├── CountingGates.js │ ├── CycleBitsGates.js │ ├── Debug_ErrorInjectionGate.js │ ├── DensityMatrixDisplay.js │ ├── Detector.js │ ├── ExponentiatingGates.js │ ├── FourierTransformGates.js │ ├── HalfTurnGates.js │ ├── Impossible_UniversalNotGate.js │ ├── IncrementGates.js │ ├── InputGates.js │ ├── InterleaveBitsGates.js │ ├── Joke_ImaginaryGate.js │ ├── Joke_MysteryGate.js │ ├── Joke_NeGate.js │ ├── Joke_ZeroGate.js │ ├── MeasurementGate.js │ ├── ModularAdditionGates.js │ ├── ModularIncrementGates.js │ ├── ModularMultiplicationGates.js │ ├── ModularMultiplyAccumulateGates.js │ ├── MultiplicationGates.js │ ├── MultiplyAccumulateGates.js │ ├── ParametrizedRotationGates.js │ ├── PhaseGradientGates.js │ ├── PivotFlipGates.js │ ├── PostSelectionGates.js │ ├── PoweringGates.js │ ├── ProbabilityDisplay.js │ ├── QuarterTurnGates.js │ ├── ReverseBitsGate.js │ ├── SampleDisplay.js │ ├── SpacerGate.js │ ├── SwapGateHalf.js │ ├── VariousXGates.js │ ├── VariousYGates.js │ ├── VariousZGates.js │ └── XorGates.js ├── issues.js ├── main.js ├── math │ ├── Axis.js │ ├── Complex.js │ ├── FormulaParser.js │ ├── Matrix.js │ ├── Point.js │ └── Rect.js ├── ui │ ├── DisplayedCircuit.js │ ├── DisplayedInspector.js │ ├── DisplayedToolbox.js │ ├── Hand.js │ ├── clear.js │ ├── exports.js │ ├── forge.js │ ├── menu.js │ ├── sim.js │ ├── title.js │ ├── undo.js │ └── url.js └── webgl │ ├── ShaderCoders.js │ ├── ShaderCoders_Base.js │ ├── ShaderCoders_intoBytes.js │ ├── ShaderCoders_intoFloats.js │ ├── Shaders.js │ ├── WglArg.js │ ├── WglConfiguredShader.js │ ├── WglContext.js │ ├── WglMortalValueSlot.js │ ├── WglShader.js │ ├── WglTexture.js │ ├── WglTexturePool.js │ ├── WglTextureTrader.js │ └── WglUtil.js ├── test ├── CircuitOperationTestUtil.js ├── KarmaTestRunner.test.js ├── TestUtil.js ├── base │ ├── Describe.test.js │ ├── DetailedError.test.js │ ├── Equate.test.js │ ├── Format.test.js │ ├── Obs.test.js │ ├── RestartableRng.test.js │ ├── Revision.test.js │ ├── Seq.test.js │ └── Util.test.js ├── circuit │ ├── CircuitComputeUtil.test.js │ ├── CircuitDefinition.test.js │ ├── CircuitShaders.test.js │ ├── CircuitStats.test.js │ ├── Controls.test.js │ ├── Gate.test.js │ ├── GateColumn.test.js │ ├── GateShaders.test.js │ ├── KetShaderUtil.test.js │ └── Serializer.test.js ├── gates │ ├── AllGates.test.js │ ├── AmplitudeDisplay.test.js │ ├── ArithmeticGates.test.js │ ├── BitCountGates.test.js │ ├── ComparisonGates.test.js │ ├── Controls.test.js │ ├── CycleBitsGates.test.js │ ├── DensityMatrixDisplay.test.js │ ├── Detector.test.js │ ├── ExponentiatingGates.test.js │ ├── FourierTransformGates.test.js │ ├── Impossible_UniversalNotGate.test.js │ ├── IncrementGates.test.js │ ├── InputGates.test.js │ ├── InterleaveBitsGates.test.js │ ├── ModularAdditionGates.test.js │ ├── ModularIncrementGates.test.js │ ├── ModularMultiplicationGates.test.js │ ├── ModularMultiplyAccumulateGates.test.js │ ├── MultiplicationGates.test.js │ ├── MultiplyAccumulateGates.test.js │ ├── ParametrizedRotationGates.test.js │ ├── PhaseGradientGates.test.js │ ├── PivotFlipGates.test.js │ ├── ProbabilityDisplay.test.js │ ├── SampleDisplay.test.js │ └── XorGates.test.js ├── math │ ├── Axis.test.js │ ├── Complex.test.js │ ├── Matrix.test.js │ ├── Point.test.js │ └── Rect.test.js ├── ui │ ├── DisplayedCircuit.test.js │ ├── MathPainter.test.js │ ├── Painter.test.js │ ├── WidgetPainter.test.js │ └── forge.test.js └── webgl │ ├── ShaderCoders.test.js │ ├── ShaderCoders_Base.test.js │ ├── ShaderCoders_intoBytes.test.js │ ├── ShaderCoders_intoFloats.test.js │ ├── Shaders.test.js │ ├── WglArg.test.js │ ├── WglShader.test.js │ ├── WglTexture.test.js │ └── WglTexturePool.test.js └── test_perf ├── CircuitStats.perf.js ├── DisplayedInspector.perf.js ├── KarmaTestRunner.perf.js ├── TestPerfUtil.js └── test_page.template.html /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: [push, pull_request] 3 | jobs: 4 | build-and-run-unit-tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-node@v1 9 | with: 10 | node-version: 12.x 11 | - run: npm install 12 | - run: grunt build-test-page 13 | - run: node PuppeteerRunTests.js 14 | screenshot-circuit: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions/setup-node@v1 19 | with: 20 | node-version: 12.x 21 | - run: npm install 22 | - run: npm run build 23 | - run: node PuppeteerScreenshotCircuit.js 24 | - uses: actions/upload-artifact@v2 25 | with: 26 | name: screenshot 27 | path: screenshot.png 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | node_modules/* 3 | out/* 4 | .eslintrc 5 | *.git_ignore.js 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | -------------------------------------------------------------------------------- /PuppeteerRunTests.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const puppeteer = require('puppeteer'); 18 | 19 | (async () => { 20 | try { 21 | const browser = await puppeteer.launch(); 22 | const page = await browser.newPage(); 23 | let caughtPageError = false; 24 | page.on('console', message => console.log(message.text())); 25 | page.on('pageerror', ({message}) => { 26 | caughtPageError = true; 27 | console.error("Page error bubbled into PuppeteerRunTests.js: " + message); 28 | }); 29 | 30 | const outDirUrl = 'file:///' + __dirname.split('\\').join('/') + '/out/'; 31 | await page.goto(outDirUrl + 'test.html#blocking'); 32 | await page.waitForSelector('#done', {timeout: 5 * 60 * 1000}); 33 | let anyFailures = await page.evaluate('__any_failures'); 34 | 35 | await browser.close(); 36 | if (anyFailures || caughtPageError) { 37 | process.exit(1); 38 | } 39 | } catch (ex) { 40 | console.error("Error bubbled up into PuppeteerRunTests.js: " + ex); 41 | process.exit(1); 42 | } 43 | })(); 44 | -------------------------------------------------------------------------------- /PuppeteerScreenshotCircuit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const puppeteer = require('puppeteer'); 18 | 19 | (async () => { 20 | try { 21 | const browser = await puppeteer.launch(); 22 | const page = await browser.newPage(); 23 | let caughtPageError = false; 24 | page.on('console', message => console.log(message.text())); 25 | page.on('pageerror', ({message}) => { 26 | caughtPageError = true; 27 | console.error("Page error bubbled into PuppeteerSampleCircuit.js: " + message); 28 | }); 29 | const outDirUrl = 'file:///' + __dirname.split('\\').join('/') + '/out/'; 30 | const circuitJson = '{"cols":[["H"],["Bloch"],["Amps1"],[],["Density"],["•","X"],["Chance2"]]}'; 31 | await page.goto(outDirUrl + 'quirk.html#circuit=' + circuitJson); 32 | await page.waitForSelector('#loading-div', {visible: false, timeout: 5 * 1000}); 33 | await page.screenshot({path: 'screenshot.png'}); 34 | await browser.close(); 35 | } catch (ex) { 36 | console.error("Error bubbled up into PuppeteerSampleCircuit.js: " + ex); 37 | process.exit(1); 38 | } 39 | })(); 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quirk Icon 2 | 3 | [![Build Status](https://travis-ci.org/Strilanc/Quirk.svg?branch=master)](https://travis-ci.org/Strilanc/Quirk) 4 | 5 | Quirk is a toy quantum circuit simulator, intended to help people in learning about quantum computing. 6 | 7 | If you want to quickly explore the behavior of a small quantum circuit, Quirk is the tool for you. 8 | There's no installing or configuring or scripting: just go to **[algassert.com/quirk](http://algassert.com/quirk)**, drag gates onto the circuit, and the output displays will update in real time. 9 | 10 | (If you're still trying to understand what a quantum circuit *even is*, then I recommend the video series [Quantum Computing for the Determined](https://www.youtube.com/playlist?list=PL1826E60FD05B44E4). 11 | Quirk assumes you already know background facts like "each wire represents a qubit".) 12 | 13 | **Defining features**: 14 | 15 | - Runs in web browsers. 16 | - Drag-and-drop circuit editing. 17 | - Reacts, simulates, and animates in real time. 18 | - Inline state displays. 19 | - Bookmarkable / linkable circuits. 20 | - Up to 16 qubits. 21 | 22 | **Notable limitations**: 23 | 24 | - Can't recohere measured qubits (because measurement is implemented as a hack based on the [deferred measurement principle](https://en.wikipedia.org/wiki/Deferred_Measurement_Principle)). 25 | 26 | **Try it out**: 27 | 28 | **[algassert.com/quirk](http://algassert.com/quirk)** 29 | 30 | # Examples 31 | 32 | **Basic usage demo**: 33 | 34 | ![Demo](/doc/README_Demo.gif) 35 | 36 | **Grover search circuit** with chance and sample displays (showing that the chance of success increases): 37 | 38 | ![Grover search](/doc/README_Grover.gif) 39 | 40 | **Quantum teleportation circuit** with Bloch sphere displays (showing that the qubit at the top has ended up at the bottom): 41 | 42 | ![Quantum teleportation](/doc/README_Teleportation.gif) 43 | 44 | # Building 45 | 46 | If you want to modify Quirk, this is how you get the code and turn your changes into working html/javascript. 47 | 48 | 1. Have [git](https://git-scm.com/) and [Node.js](https://nodejs.org/en/download/) installed. 49 | 50 | `sudo add-apt-repository universe` 51 | 52 | `sudo apt-get update` 53 | 54 | `sudo apt-get install --yes git npm nodejs-legacy` 55 | 56 | 2. Clone the repository. 57 | 58 | `git clone https://github.com/Strilanc/Quirk.git` 59 | 60 | 3. Install the dev dependencies. 61 | 62 | `cd Quirk` 63 | 64 | `npm install` 65 | 66 | 4. (*Optional*) Make your changes. Run the tests. 67 | 68 | `npm run test-firefox` 69 | 70 | 5. Build the output. 71 | 72 | `npm run build` 73 | 74 | 6. Confirm the output works by opening `out/quirk.html` with a web browser. 75 | 76 | `firefox out/quirk.html` 77 | 78 | 7. Copy `out/quirk.html` to wherever you want. 79 | 80 | # Disclaimer 81 | 82 | Quirk is not an official Google product. 83 | -------------------------------------------------------------------------------- /doc/MANUAL_amp-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_amp-display.png -------------------------------------------------------------------------------- /doc/MANUAL_bloch-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_bloch-display.png -------------------------------------------------------------------------------- /doc/MANUAL_chance-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_chance-display.png -------------------------------------------------------------------------------- /doc/MANUAL_circuit-editing-area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_circuit-editing-area.png -------------------------------------------------------------------------------- /doc/MANUAL_controlled-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_controlled-display.png -------------------------------------------------------------------------------- /doc/MANUAL_controlled-epr-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_controlled-epr-display.png -------------------------------------------------------------------------------- /doc/MANUAL_density-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_density-display.png -------------------------------------------------------------------------------- /doc/MANUAL_measurement-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_measurement-types.png -------------------------------------------------------------------------------- /doc/MANUAL_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_menu.png -------------------------------------------------------------------------------- /doc/MANUAL_state-channel-duality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_state-channel-duality.png -------------------------------------------------------------------------------- /doc/MANUAL_various-displays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/MANUAL_various-displays.png -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | **Basic Actions** 2 | 3 | - **add gate**: `drag` gate from toolbox to circuit 4 | - **move gate**: `drag` gate in circuit 5 | - **remove gate**: `drag` gate out of circuit **OR** `middle-click` gate 6 | - **undo**: `ctrl + Z` **OR** click 'undo' button 7 | - **redo**: `ctrl + shift + Z` **OR** `ctrl + Y` **OR** click 'redo' button 8 | - **save circuit**: bookmark the page with your browser 9 | - **load circuit**: open the bookmark 10 | - **add qubit**: `drag` gate onto extra wire that appears while dragging 11 | - **remove qubit**: re-arrange gates so that the bottom wire is unused 12 | - **show intermediate state**: `drag` a display gate onto the circuit 13 | - **view tips**: `hover` with mouse **OR** awkwardly tap-hold with finger 14 | 15 | **Advanced Actions** 16 | 17 | - **copy gate**: `shift + drag` gate in circuit 18 | - **move column**: `ctrl + drag` in circuit 19 | - **copy column**: `ctrl + shift + drag` in circuit 20 | - **create custom gate**: click 'Make Gate' button 21 | - **remove custom gate**: [crummy support] have to use undo or clear all or manually edit URL 22 | 23 | **Conventions** 24 | 25 | - Coordinates 26 | - Right-handed 27 | - X is +right/-left 28 | - Y is +forward/-backward 29 | - Z is +up/-down 30 | - Ordering 31 | - Top wire is the low bit. Bottom wire is the high bit. 32 | - Kets are big-endian. |00101⟩ is 5, not 20. 33 | - Listed/grided values are in ascending row-major order from top left to bottom right. 34 | - Colors 35 | - Blue: amplitudes 36 | - Green: probabilities / densities 37 | - Yellow: change / varying 38 | - Orange: focused 39 | - Red: error / attention 40 | -------------------------------------------------------------------------------- /doc/README_Demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/README_Demo.gif -------------------------------------------------------------------------------- /doc/README_Grover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/README_Grover.gif -------------------------------------------------------------------------------- /doc/README_Teleportation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/README_Teleportation.gif -------------------------------------------------------------------------------- /doc/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Strilanc/Quirk/8833791294e642795c8717038e84940a74b19a64/doc/favicon.ico -------------------------------------------------------------------------------- /html/error.partial.html: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /html/export.partial.html: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /karma.test.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = function(config) { 18 | config.set({ 19 | basePath: '', 20 | frameworks: [], 21 | files: ['out/test.js'], 22 | exclude: [], 23 | preprocessors: {}, 24 | reporters: ['dots'], 25 | port: 19876, 26 | colors: true, 27 | browserNoActivityTimeout: 30000, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: false, 30 | browsers: ['Chrome', 'Firefox'], 31 | singleRun: true 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /karma.test_perf.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = function(config) { 18 | config.set({ 19 | basePath: '', 20 | frameworks: [], 21 | files: ['out/test_perf.js'], 22 | exclude: [], 23 | preprocessors: {}, 24 | reporters: ['dots'], 25 | port: 19876, 26 | colors: true, 27 | browserNoActivityTimeout: 30000, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: false, 30 | browsers: ['Chrome', 'Firefox'], 31 | singleRun: true 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quirk-quantum-circuit-simulator", 3 | "title": "Quirk", 4 | "description": "A drag-and-drop toy for exploring and understanding small quantum circuits.", 5 | "license": "Apache-2.0", 6 | "version": "2.3.2", 7 | "homepage": "https://github.com/Strilanc/Quirk", 8 | "bugs": { 9 | "url": "https://github.com/Strilanc/Quirk/issues" 10 | }, 11 | "devDependencies": { 12 | "grunt": "~1.3.0", 13 | "grunt-cli": "~1.3.2", 14 | "grunt-contrib-clean": "~2.0.0", 15 | "grunt-contrib-concat": "~1.0.1", 16 | "grunt-contrib-copy": "~1.0.0", 17 | "grunt-contrib-uglify": "~5.0.0", 18 | "grunt-karma": "~4.0.0", 19 | "grunt-traceur": "~0.5.5", 20 | "karma": "~5.2.2", 21 | "karma-chrome-launcher": "~3.1.0", 22 | "karma-firefox-launcher": "~1.3.0", 23 | "traceur": "0.0.111", 24 | "puppeteer": "^5.3.0" 25 | }, 26 | "scripts": { 27 | "build": "grunt build-src", 28 | "test": "grunt test", 29 | "test-chrome": "grunt test-chrome", 30 | "test-firefox": "grunt test-firefox", 31 | "test-travis": "grunt test-travis" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/Strilanc/Quirk.git" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Configuration parameters for quantum circuit visualizer. 19 | */ 20 | class Config {} 21 | 22 | Config.EMPTY_CIRCUIT_TITLE = 'Quirk: Quantum Circuit Simulator'; 23 | 24 | // Each qubit (when actually used) doubles the cost of simulating each gate applied to the circuit. 25 | // Also each qubit tends to increase the amount of accuracy required. 26 | // I see obvious errors when I set this to 20, and things get pretty laggy past 16. 27 | // Beware setting it too high. 28 | Config.MAX_WIRE_COUNT = 16; 29 | Config.SIMPLE_SUPERPOSITION_DRAWING_WIRE_THRESHOLD = 14; 30 | 31 | Config.MIN_WIRE_COUNT = 2; 32 | Config.MIN_COL_COUNT = 5; 33 | Config.URL_CIRCUIT_PARAM_KEY = 'circuit'; 34 | 35 | // Gate background colors. 36 | Config.GATE_FILL_COLOR = 'white'; 37 | Config.HIGHLIGHTED_GATE_FILL_COLOR = '#FB7'; 38 | Config.TIME_DEPENDENT_HIGHLIGHT_COLOR = '#FFC'; 39 | 40 | // Mixed-state displays are green. 41 | Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR = '#4F4'; 42 | Config.DISPLAY_GATE_BACK_COLOR = '#EFE'; 43 | Config.DISPLAY_GATE_FORE_COLOR = '#3F3'; 44 | 45 | // Changes are yellow. 46 | Config.OPERATION_BACK_COLOR = '#FFE'; 47 | Config.OPERATION_FORE_COLOR = '#FF0'; 48 | 49 | // Pure-state displays are cyan. 50 | Config.SUPERPOSITION_BACK_COLOR = '#EFF'; 51 | Config.SUPERPOSITION_MID_COLOR = '#8FF'; 52 | Config.SUPERPOSITION_FORE_COLOR = '#0BB'; 53 | 54 | // Time constants. 55 | Config.CYCLE_DURATION_MS = 8000; // How long it takes for evolving gates to cycle, in milliseconds. 56 | Config.TIME_CACHE_GRANULARITY = 196; // The number of buckets the cycle is divided into. 57 | Config.REDRAW_COOLDOWN_MILLIS = 10; // Milliseconds. Rate-limit on redraws. Long draws pad this limit. 58 | 59 | /** Half of the span of a drawn gate, width-wise and height-wise. 60 | * @type {!number} */ 61 | Config.GATE_RADIUS = 20; 62 | Config.WIRE_SPACING = 50; 63 | 64 | Config.BACKGROUND_COLOR = 'white'; 65 | Config.BACKGROUND_COLOR_CIRCUIT = 'white'; 66 | 67 | // Toolbox layout. 68 | Config.BACKGROUND_COLOR_TOOLBOX = '#CCC'; 69 | Config.TOOLBOX_GATE_SPACING = 2; 70 | Config.TOOLBOX_GROUP_SPACING = 24 - Config.TOOLBOX_GATE_SPACING; 71 | Config.TOOLBOX_GATE_SPAN = Config.GATE_RADIUS * 2 + Config.TOOLBOX_GATE_SPACING; 72 | Config.TOOLBOX_GROUP_SPAN = Config.TOOLBOX_GATE_SPAN * 2 + Config.TOOLBOX_GROUP_SPACING; 73 | Config.TOOLBOX_MARGIN_X = 35; 74 | Config.TOOLBOX_MARGIN_Y = 18; 75 | 76 | /** 77 | * Some tooltips end up looking terrible without available vertical space. 78 | * (e.g. the error box might not fit, or the gate tips might get squashed) 79 | * @type {number} 80 | */ 81 | Config.MINIMUM_CANVAS_HEIGHT = 400; 82 | 83 | Config.SUPPRESSED_GLSL_WARNING_PATTERNS = []; 84 | 85 | // Draw constants. 86 | Config.DEFAULT_FILL_COLOR = 'white'; 87 | Config.DEFAULT_STROKE_COLOR = 'black'; 88 | Config.DEFAULT_TEXT_COLOR = 'black'; 89 | Config.DEFAULT_FONT_SIZE = 12; 90 | Config.DEFAULT_FONT_FAMILY = 'sans-serif'; 91 | Config.DEFAULT_STROKE_THICKNESS = 1; 92 | 93 | // Calling WebGLRenderingContext.getError forces a CPU/GPU sync. It's very expensive. 94 | Config.CHECK_WEB_GL_ERRORS_EVEN_ON_HOT_PATHS = false; 95 | Config.SEMI_STABLE_RANDOM_VALUE_LIFETIME_MILLIS = 300; 96 | 97 | Config.IGNORED_WEBGL_INFO_TERMS = []; 98 | 99 | export {Config} 100 | -------------------------------------------------------------------------------- /src/base/DetailedError.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe} from "./Describe.js" 18 | 19 | let CONSTRUCTOR_CALLS_NESTING = 0; 20 | 21 | /** 22 | * A generic error with an attached payload of details for context. 23 | */ 24 | class DetailedError extends Error { 25 | /** 26 | * @param {!string} message 27 | * @param {*} detailsObj 28 | */ 29 | constructor(message, detailsObj) { 30 | super(message); 31 | /** @type {*} */ 32 | this.detailsObj = detailsObj; 33 | /** @type {!string} */ 34 | this.name = 'Error'; 35 | /** @type {!string} */ 36 | this.message = message; 37 | /** @type {undefined|!string} */ 38 | this.stack = new Error().stack; 39 | if (this.stack !== undefined) { 40 | this.stack = this.stack.replace(/^Error\n\s+at new DetailedError (\S+)\s?\n\s+at /, '\n '); 41 | } 42 | 43 | CONSTRUCTOR_CALLS_NESTING++; 44 | try { 45 | /** @type {!string} */ 46 | this.details = CONSTRUCTOR_CALLS_NESTING === 1 ? 47 | describe(this.detailsObj) : 48 | "(failed to describe detailsObj due to possibly re-entrancy)"; 49 | } catch (ex) { 50 | console.error(ex); 51 | this.details = "(failed to describe detailsObj, see the console for details)"; 52 | } finally { 53 | CONSTRUCTOR_CALLS_NESTING--; 54 | } 55 | } 56 | 57 | toString() { 58 | return `${super.toString()}\nDetails: ${this.details}`; 59 | } 60 | } 61 | 62 | export {DetailedError} 63 | -------------------------------------------------------------------------------- /src/base/RestartableRng.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * A random number generator that records its results, so you can make a restarted copy. 19 | */ 20 | class RestartableRng { 21 | /** 22 | * @private 23 | */ 24 | constructor() { 25 | /** 26 | * @type {!Array.} 27 | * @private 28 | */ 29 | this._cache = []; 30 | /** 31 | * @type {!int} 32 | * @private 33 | */ 34 | this._next = 0; 35 | } 36 | 37 | /** 38 | * @returns {!RestartableRng} 39 | */ 40 | restarted() { 41 | let result = new RestartableRng(); 42 | result._cache = this._cache; 43 | return result; 44 | } 45 | 46 | /** 47 | * @returns {!number} A random number uniformly sampled from [0, 1). 48 | */ 49 | random() { 50 | let p = this._next++; 51 | if (p >= this._cache.length) { 52 | this._cache.push(Math.random()); 53 | } 54 | return this._cache[p]; 55 | } 56 | } 57 | 58 | export {RestartableRng} 59 | -------------------------------------------------------------------------------- /src/browser/Clipboard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @param {!HTMLElement} element 19 | * @throws 20 | */ 21 | function selectAndCopyToClipboard(element) { 22 | if (document.selection) { 23 | //noinspection XHTMLIncompatabilitiesJS 24 | let range = document.body.createTextRange(); 25 | range.moveToElementText(element); 26 | range.select(); 27 | } else if (window.getSelection) { 28 | let range = document.createRange(); 29 | range.selectNodeContents(element); 30 | window.getSelection().removeAllRanges(); 31 | window.getSelection().addRange(range); 32 | } 33 | 34 | if (!document.execCommand('copy')) { 35 | throw new Error("execCommand failed"); 36 | } 37 | } 38 | 39 | export {selectAndCopyToClipboard} 40 | -------------------------------------------------------------------------------- /src/browser/EventUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Observable} from "../base/Obs.js" 18 | 19 | /** 20 | * @param {!HTMLInputElement} textBox 21 | * @returns {!Observable.} 22 | */ 23 | function textEditObservable(textBox) { 24 | return Observable.of( 25 | Observable.elementEvent(textBox, 'change'), 26 | Observable.elementEvent(textBox, 'keyup'), 27 | Observable.elementEvent(textBox, 'click'), 28 | Observable.elementEvent(textBox, 'paste'), 29 | Observable.elementEvent(textBox, 'input') 30 | ).flatten().map(e => textBox.value).whenDifferent(); 31 | } 32 | 33 | export {textEditObservable}; 34 | -------------------------------------------------------------------------------- /src/browser/SaveFile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @param {!string} name 19 | * @param {!string} content 20 | */ 21 | function saveFile(name, content) { 22 | //noinspection JSUnresolvedVariable 23 | if (navigator.msSaveBlob) { 24 | //noinspection JSUnresolvedFunction 25 | navigator.msSaveBlob(new Blob([content], {type: 'text/html;charset=UTF-8'}), name); 26 | return; 27 | } 28 | 29 | let anchor = document.createElement("a"); 30 | //noinspection JSUnresolvedVariable,JSUnresolvedFunction 31 | anchor.href = window.URL !== undefined ? 32 | window.URL.createObjectURL(new Blob([content], {type: 'text/html;charset=UTF-8'})) : 33 | 'data:application/octet-stream,' + encodeURI(moddedHtml); 34 | anchor.download = name; 35 | try { 36 | //noinspection XHTMLIncompatabilitiesJS 37 | document.body.appendChild(anchor); 38 | anchor.click(); 39 | } finally { 40 | //noinspection XHTMLIncompatabilitiesJS 41 | document.body.removeChild(anchor); 42 | } 43 | } 44 | 45 | export {saveFile}; 46 | -------------------------------------------------------------------------------- /src/browser/TouchScrollBlocker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Rect} from "../math/Rect.js" 18 | 19 | class TouchScrollBlocker { 20 | /** 21 | * @param {HTMLElement} parentElement 22 | */ 23 | constructor(parentElement) { 24 | /** 25 | * @type {!HTMLElement} 26 | * @private 27 | */ 28 | this._parentElement = parentElement; 29 | 30 | /** 31 | * @type {!{div: !HTMLDivElement, area: !Rect}} 32 | * @private 33 | */ 34 | this._curBlockers = []; 35 | 36 | /** 37 | * @type {!int} 38 | * @private 39 | */ 40 | this._curShowing = 0; 41 | } 42 | 43 | //noinspection Eslint 44 | /** 45 | * @param {!Array.} desiredBlockers 46 | * @param {undefined|!string} overrideCursorStyle 47 | */ 48 | setBlockers(desiredBlockers, overrideCursorStyle) { 49 | while (this._curBlockers.length < desiredBlockers.length) { 50 | let blockerDiv = document.createElement('div'); 51 | blockerDiv.style.touchAction = 'none'; 52 | blockerDiv.style.position = 'absolute'; 53 | blockerDiv.style.opacity = 0.0001; 54 | this._parentElement.appendChild(blockerDiv); 55 | this._curBlockers.push({div: blockerDiv, area: undefined}); 56 | } 57 | 58 | // Positioning. 59 | for (let i = 0; i < desiredBlockers.length; i++) { 60 | let desiredArea = desiredBlockers[i].rect; 61 | let desiredCursor = overrideCursorStyle || desiredBlockers[i].cursor || 'auto'; 62 | let cur = this._curBlockers[i]; 63 | let style = cur.div.style; 64 | 65 | if (!desiredArea.isEqualTo(cur.area)) { 66 | cur.area = desiredArea; 67 | style.left = desiredArea.x + "px"; 68 | style.top = desiredArea.y + "px"; 69 | style.width = desiredArea.w + "px"; 70 | style.height = desiredArea.h + "px"; 71 | } 72 | if (style.cursor !== desiredCursor) { 73 | style.cursor = desiredCursor; 74 | } 75 | } 76 | 77 | // Visibility. 78 | while (this._curShowing < desiredBlockers.length) { 79 | this._curBlockers[this._curShowing].div.style.display = 'inline'; 80 | this._curShowing++; 81 | } 82 | while (this._curShowing > desiredBlockers.length) { 83 | this._curShowing--; 84 | this._curBlockers[this._curShowing].div.style.display = 'none'; 85 | } 86 | } 87 | } 88 | 89 | export {TouchScrollBlocker} 90 | -------------------------------------------------------------------------------- /src/circuit/CustomGateSet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {DetailedError} from "../base/DetailedError.js" 18 | 19 | class CustomGateSet { 20 | /** 21 | * @param {!Gate} gates 22 | */ 23 | constructor(...gates) { 24 | /** @type {!Array.} */ 25 | this.gates = gates; 26 | } 27 | 28 | /** 29 | * @param {!Gate} gate 30 | * @returns {!CustomGateSet} 31 | */ 32 | withGate(gate) { 33 | if (!gate.serializedId.startsWith("~")) { 34 | throw new DetailedError("Custom gates' serialized id must start with '~'.", {id: gate.serializedId, gate}); 35 | } 36 | if (this.findGateWithSerializedId(gate.serializedId)) { 37 | throw new DetailedError("Duplicate serialized id.", {gate}); 38 | } 39 | return new CustomGateSet(...this.gates, gate); 40 | } 41 | 42 | /** 43 | * @param {!String} id 44 | * @returns {undefined|!Gate} 45 | */ 46 | findGateWithSerializedId(id) { 47 | for (let g of this.gates) { 48 | if (g.serializedId === id) { 49 | return g; 50 | } 51 | } 52 | return undefined; 53 | } 54 | } 55 | 56 | export {CustomGateSet} 57 | -------------------------------------------------------------------------------- /src/circuit/GateCheckArgs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Values used by gate disable reason finder functions. 19 | */ 20 | class GateCheckArgs { 21 | /** 22 | * @param {!Gate} gate 23 | * @param {!GateColumn} innerColumn 24 | * @param {!int} outerRow 25 | * @param {!int} measuredMask 26 | * @param {!Map.} context 27 | * @param {!boolean} isNested 28 | */ 29 | constructor(gate, 30 | innerColumn, 31 | outerRow, 32 | measuredMask, 33 | context, 34 | isNested) { 35 | /** @type {!Gate} */ 36 | this.gate = gate; 37 | /** @type {!GateColumn} */ 38 | this.innerColumn = innerColumn; 39 | /** @type {!int} */ 40 | this.outerRow = outerRow; 41 | /** @type {!int} */ 42 | this.measuredMask = measuredMask; 43 | /** @type {!Map.} */ 44 | this.context = context; 45 | /** @type {!boolean} */ 46 | this.isNested = isNested; 47 | } 48 | } 49 | 50 | export {GateCheckArgs} 51 | -------------------------------------------------------------------------------- /src/draw/CachablePainting.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Painter} from "./Painter.js" 18 | import {RestartableRng} from "../base/RestartableRng.js" 19 | 20 | const fixedRng = new RestartableRng(); 21 | 22 | /** 23 | * A drawing process that always has the same result, so its output can be cached and pasted instead of recreated anew. 24 | */ 25 | class CachablePainting { 26 | /** 27 | * @param {!function(key: *) : !{width: !int, height: !int}} sizeFunc 28 | * @param {!function(painter: !Painter | !(function(!Painter, !string): void)) : void} drawingFunc 29 | */ 30 | constructor(sizeFunc, drawingFunc) { 31 | /** @type {!function(key: *) : !{width: !int, height: !int}} */ 32 | this.sizeFunc = sizeFunc; 33 | /** 34 | * @type {!(function(!Painter): void) | !(function(!Painter, !string): void)} 35 | * @private 36 | */ 37 | this._drawingFunc = drawingFunc; 38 | /** 39 | * @type {!Map.} 40 | * @private 41 | */ 42 | this._cachedCanvases = new Map(); 43 | } 44 | 45 | /** 46 | * @param {!int} x 47 | * @param {!int} y 48 | * @param {!Painter} painter 49 | * @param {!*=} key 50 | */ 51 | paint(x, y, painter, key=undefined) { 52 | if (!this._cachedCanvases.has(key)) { 53 | let canvas = /** @type {!HTMLCanvasElement} */ document.createElement('canvas'); 54 | let {width, height} = this.sizeFunc(key); 55 | canvas.width = width; 56 | canvas.height = height; 57 | this._drawingFunc(new Painter(canvas, fixedRng.restarted()), key); 58 | this._cachedCanvases.set(key, canvas); 59 | } 60 | painter.ctx.drawImage(this._cachedCanvases.get(key), x, y); 61 | } 62 | } 63 | 64 | export {CachablePainting} 65 | -------------------------------------------------------------------------------- /src/draw/GateDrawParams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Values used by the various gate drawing strategies. 19 | */ 20 | class GateDrawParams { 21 | /** 22 | * @param {!Painter} painter 23 | * @param {!Hand} hand 24 | * @param {!boolean} isInToolbox 25 | * @param {!boolean} isHighlighted 26 | * @param {!boolean} isResizeShowing 27 | * @param {!boolean} isResizeHighlighted 28 | * @param {!Rect} rect 29 | * @param {!Gate} gate 30 | * @param {!CircuitStats} stats 31 | * @param {undefined|!{row: !int, col: !int}} positionInCircuit 32 | * @param {!Array.} focusPoints 33 | * @param {undefined|*} customStatsForCircuitPos 34 | */ 35 | constructor(painter, 36 | hand, 37 | isInToolbox, 38 | isHighlighted, 39 | isResizeShowing, 40 | isResizeHighlighted, 41 | rect, 42 | gate, 43 | stats, 44 | positionInCircuit, 45 | focusPoints, 46 | customStatsForCircuitPos) { 47 | /** @type {!Painter} */ 48 | this.painter = painter; 49 | /** @type {!Hand} */ 50 | this.hand = hand; 51 | /** @type {!boolean} */ 52 | this.isInToolbox = isInToolbox; 53 | /** @type {!boolean} */ 54 | this.isHighlighted = isHighlighted; 55 | /** @type {!boolean} */ 56 | this.isResizeShowing = isResizeShowing; 57 | /** @type {!boolean} */ 58 | this.isResizeHighlighted = isResizeHighlighted; 59 | /** @type {!Rect} */ 60 | this.rect = rect; 61 | /** @type {!Gate} */ 62 | this.gate = gate; 63 | /** @type {!CircuitStats} */ 64 | this.stats = stats; 65 | /** @type {undefined|!{row: !int, col: !int}} */ 66 | this.positionInCircuit = positionInCircuit; 67 | /** @type {!Array.} */ 68 | this.focusPoints = focusPoints; 69 | /** @type {undefined|*} */ 70 | this.customStats = customStatsForCircuitPos; 71 | } 72 | 73 | /** 74 | * @param {!string} key 75 | * @returns {undefined|*} 76 | */ 77 | getGateContext(key) { 78 | if (this.positionInCircuit === undefined) { 79 | return undefined; 80 | } 81 | 82 | return this.stats.circuitDefinition. 83 | colCustomContextFromGates(this.positionInCircuit.col, 0). 84 | get(key); 85 | } 86 | } 87 | 88 | export {GateDrawParams} 89 | -------------------------------------------------------------------------------- /src/gates/BitCountGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {Gate} from "../circuit/Gate.js" 19 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 20 | import {Util} from "../base/Util.js" 21 | import {WglArg} from "../webgl/WglArg.js" 22 | 23 | let BitCountGates = {}; 24 | 25 | const POP_COUNT_SHADER = ketShaderPermute( 26 | ` 27 | uniform float factor; 28 | ${ketInputGateShaderCode('A')} 29 | `, 30 | ` 31 | float d = read_input_A(); 32 | float popcnt = 0.0; 33 | for (int i = 0; i < ${Config.MAX_WIRE_COUNT}; i++) { 34 | popcnt += mod(d, 2.0); 35 | d = floor(d / 2.0); 36 | } 37 | float offset = mod(popcnt * factor, span); 38 | return mod(out_id + span - offset, span);`); 39 | 40 | BitCountGates.PlusBitCountAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 41 | setSerializedIdAndSymbol("+cntA" + span). 42 | setSymbol("+1s(A)"). 43 | setTitle("Bit Count Gate"). 44 | setBlurb("Counts the number of ON bits in input A and adds that into this output."). 45 | setRequiredContextKeys("Input Range A"). 46 | setActualEffectToShaderProvider(ctx => POP_COUNT_SHADER.withArgs( 47 | ...ketArgs(ctx, span, ['A']), 48 | WglArg.float("factor", +1))). 49 | setKnownEffectToParametrizedPermutation((t, a) => (t + Util.numberOfSetBits(a)) & ((1 << span) - 1))); 50 | 51 | BitCountGates.MinusBitCountAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 52 | setAlternateFromFamily(BitCountGates.PlusBitCountAFamily). 53 | setSerializedIdAndSymbol("-cntA" + span). 54 | setSymbol("-1s(A)"). 55 | setTitle("Bit Un-Count Gate"). 56 | setBlurb("Counts the number of ON bits in input A and subtracts that into this output."). 57 | setRequiredContextKeys("Input Range A"). 58 | setActualEffectToShaderProvider(ctx => POP_COUNT_SHADER.withArgs( 59 | ...ketArgs(ctx, span, ['A']), 60 | WglArg.float("factor", -1))). 61 | setKnownEffectToParametrizedPermutation((t, a) => (t - Util.numberOfSetBits(a)) & ((1 << span) - 1))); 62 | 63 | BitCountGates.all = [ 64 | ...BitCountGates.PlusBitCountAFamily.all, 65 | ...BitCountGates.MinusBitCountAFamily.all 66 | ]; 67 | 68 | export {BitCountGates} 69 | -------------------------------------------------------------------------------- /src/gates/Debug_ErrorInjectionGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {DetailedError} from "../base/DetailedError.js" 18 | import {GateBuilder} from "../circuit/Gate.js" 19 | import {GatePainting} from "../draw/GatePainting.js" 20 | 21 | let ErrorInjectionGate = new GateBuilder(). 22 | setSerializedId("__error__"). 23 | setSymbol("ERR!"). 24 | setTitle("Error Injection Gate"). 25 | setBlurb("Throws an exception during circuit stat computations, for testing error paths."). 26 | setDrawer(GatePainting.MAKE_HIGHLIGHTED_DRAWER('red', 'red')). 27 | setActualEffectToUpdateFunc(ctx => { 28 | throw new DetailedError("Applied an Error Injection Gate", {qubit: ctx.row}); 29 | }). 30 | promiseEffectIsStable(). 31 | gate; 32 | 33 | export {ErrorInjectionGate} 34 | -------------------------------------------------------------------------------- /src/gates/Impossible_UniversalNotGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {ketArgs, ketShader} from "../circuit/KetShaderUtil.js" 19 | import {WglConfiguredShader} from "../webgl/WglConfiguredShader.js" 20 | 21 | /** 22 | * @param {!CircuitEvalContext} ctx 23 | * @returns {!WglConfiguredShader} 24 | */ 25 | let universalNot = ctx => UNIVERSAL_NOT_SHADER.withArgs(...ketArgs(ctx)); 26 | const UNIVERSAL_NOT_SHADER = ketShader( 27 | '', 28 | 'vec2 other = inp(1.0 - out_id); return vec2(other.x, -other.y) * (1.0 - 2.0 * out_id);', 29 | 1); 30 | 31 | let UniversalNotGate = new GateBuilder(). 32 | setSerializedId("__unstable__UniversalNot"). 33 | setSymbol("UniNot"). 34 | setTitle("Universal Not Gate"). 35 | setBlurb("Mirrors through the origin of the Bloch sphere.\nImpossible in practice."). 36 | setActualEffectToShaderProvider(universalNot). 37 | promiseEffectIsStable(). 38 | gate; 39 | 40 | export {universalNot, UniversalNotGate} 41 | -------------------------------------------------------------------------------- /src/gates/IncrementGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {ketArgs, ketShaderPermute} from "../circuit//KetShaderUtil.js" 19 | import {WglArg} from "../webgl/WglArg.js" 20 | 21 | let IncrementGates = {}; 22 | 23 | const offsetShader = ketShaderPermute( 24 | 'uniform float amount;', 25 | 'return mod(out_id - amount + span, span);'); 26 | 27 | IncrementGates.IncrementFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 28 | setSerializedId("inc" + span). 29 | setSymbol("+1"). 30 | setTitle("Increment Gate"). 31 | setBlurb("Adds 1 to the little-endian number represented by a block of qubits."). 32 | setActualEffectToShaderProvider(ctx => offsetShader.withArgs( 33 | ...ketArgs(ctx, span), 34 | WglArg.float("amount", +1))). 35 | setKnownEffectToPermutation(t => (t + 1) & ((1 << span) - 1))); 36 | 37 | IncrementGates.DecrementFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 38 | setAlternateFromFamily(IncrementGates.IncrementFamily). 39 | setSerializedId("dec" + span). 40 | setSymbol("−1"). 41 | setTitle("Decrement Gate"). 42 | setBlurb("Subtracts 1 from the little-endian number represented by a block of qubits."). 43 | setActualEffectToShaderProvider(ctx => offsetShader.withArgs( 44 | ...ketArgs(ctx, span), 45 | WglArg.float("amount", -1))). 46 | setKnownEffectToPermutation(t => (t - 1) & ((1 << span) - 1))); 47 | 48 | IncrementGates.all = [ 49 | ...IncrementGates.IncrementFamily.all, 50 | ...IncrementGates.DecrementFamily.all, 51 | ]; 52 | 53 | export {IncrementGates, offsetShader} 54 | -------------------------------------------------------------------------------- /src/gates/Joke_ImaginaryGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | import {Complex} from "../math/Complex.js" 20 | import {GatePainting} from "../draw/GatePainting.js" 21 | 22 | const ImaginaryGate = new GateBuilder(). 23 | setSerializedIdAndSymbol("i"). 24 | setTitle("Imaginary Gate"). 25 | setBlurb("Phases everything by i."). 26 | setDrawer(args => { 27 | GatePainting.paintLocationIndependentFrame(args); 28 | GatePainting.paintGateSymbol(args); 29 | }). 30 | setKnownEffectToMatrix(Matrix.square(Complex.I, 0, 0, Complex.I)). 31 | gate; 32 | 33 | const AntiImaginaryGate = new GateBuilder(). 34 | setAlternate(ImaginaryGate). 35 | setSerializedIdAndSymbol("-i"). 36 | setTitle("Anti-Imaginary Gate"). 37 | setBlurb("Phases everything by -i."). 38 | setDrawer(args => { 39 | GatePainting.paintLocationIndependentFrame(args); 40 | GatePainting.paintGateSymbol(args); 41 | }). 42 | setKnownEffectToMatrix(Matrix.square(Complex.I.neg(), 0, 0, Complex.I.neg())). 43 | gate; 44 | 45 | const SqrtImaginaryGate = new GateBuilder(). 46 | setSerializedIdAndSymbol("√i"). 47 | setTitle("Half Imaginary Gate"). 48 | setBlurb("Phases everything by √i."). 49 | setDrawer(args => { 50 | GatePainting.paintLocationIndependentFrame(args); 51 | GatePainting.paintGateSymbol(args); 52 | }). 53 | setKnownEffectToMatrix(Matrix.square(1, 0, 0, 1).times(new Complex(Math.sqrt(0.5), Math.sqrt(0.5)))). 54 | gate; 55 | 56 | const AntiSqrtImaginaryGate = new GateBuilder(). 57 | setAlternate(SqrtImaginaryGate). 58 | setSerializedIdAndSymbol("√-i"). 59 | setTitle("Half Anti-Imaginary Gate"). 60 | setBlurb("Phases everything by √-i."). 61 | setDrawer(args => { 62 | GatePainting.paintLocationIndependentFrame(args); 63 | GatePainting.paintGateSymbol(args); 64 | }). 65 | setKnownEffectToMatrix(Matrix.square(1, 0, 0, 1).times(new Complex(Math.sqrt(0.5), -Math.sqrt(0.5)))). 66 | gate; 67 | 68 | export {AntiImaginaryGate, ImaginaryGate, SqrtImaginaryGate, AntiSqrtImaginaryGate} 69 | -------------------------------------------------------------------------------- /src/gates/Joke_MysteryGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Complex} from "../math/Complex.js" 18 | import {GateBuilder} from "../circuit/Gate.js" 19 | import {GatePainting} from "../draw/GatePainting.js" 20 | import {Matrix} from "../math/Matrix.js" 21 | 22 | let MysteryGateSymbol = "?"; 23 | 24 | let MysteryGateMakerWithMatrix = matrix => new GateBuilder(). 25 | setSerializedIdAndSymbol(MysteryGateSymbol). 26 | setTitle("Mystery Gate"). 27 | setBlurb("Different every time.\n(Use shift+drag to copy circuit gates.)"). 28 | setDrawer(GatePainting.MATRIX_SYMBOL_DRAWER_EXCEPT_IN_TOOLBOX). 29 | setKnownEffectToMatrix(matrix). 30 | gate; 31 | 32 | let MysteryGateMaker = () => MysteryGateMakerWithMatrix(Matrix.square( 33 | new Complex(Math.random() - 0.5, Math.random() - 0.5), 34 | new Complex(Math.random() - 0.5, Math.random() - 0.5), 35 | new Complex(Math.random() - 0.5, Math.random() - 0.5), 36 | new Complex(Math.random() - 0.5, Math.random() - 0.5) 37 | ).closestUnitary(0.00001)); 38 | 39 | export {MysteryGateSymbol, MysteryGateMaker, MysteryGateMakerWithMatrix}; 40 | -------------------------------------------------------------------------------- /src/gates/Joke_NeGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | import {Point} from "../math/Point.js" 20 | import {GatePainting} from "../draw/GatePainting.js" 21 | 22 | const NeGate = new GateBuilder(). 23 | setSerializedId("NeGate"). 24 | setTitle("Ne-Gate"). 25 | setBlurb("Negates all amplitudes."). 26 | setDrawer(args => { 27 | GatePainting.paintLocationIndependentFrame(args); 28 | let {x, y} = args.rect.center(); 29 | args.painter.strokeLine(new Point(x - 6, y), new Point(x + 6, y), 'black', 2); 30 | }). 31 | setKnownEffectToMatrix(Matrix.square(-1, 0, 0, -1)). 32 | gate; 33 | 34 | export {NeGate} 35 | -------------------------------------------------------------------------------- /src/gates/Joke_ZeroGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {GatePainting} from "../draw/GatePainting.js" 19 | import {Matrix} from "../math/Matrix.js" 20 | 21 | /** @type {!Gate} */ 22 | const ZeroGate = new GateBuilder(). 23 | setSerializedIdAndSymbol("0"). 24 | setTitle("Nothing Gate"). 25 | setBlurb("Destroys the universe."). 26 | setDrawer(GatePainting.makeLocationIndependentGateDrawer('#666')). 27 | setKnownEffectToMatrix(Matrix.square(0, 0, 0, 0)). 28 | gate; 29 | 30 | export {ZeroGate} 31 | -------------------------------------------------------------------------------- /src/gates/MeasurementGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {GateBuilder} from "../circuit/Gate.js" 19 | import {GatePainting} from "../draw/GatePainting.js" 20 | 21 | /** 22 | * @param {!GateDrawParams} args 23 | */ 24 | function drawMeasurementGate(args) { 25 | let backColor = Config.GATE_FILL_COLOR; 26 | if (args.isHighlighted) { 27 | backColor = Config.HIGHLIGHTED_GATE_FILL_COLOR; 28 | } 29 | args.painter.fillRect(args.rect, backColor); 30 | GatePainting.paintOutline(args); 31 | 32 | const τ = Math.PI * 2; 33 | let r = args.rect.w*0.4; 34 | let {x, y} = args.rect.center(); 35 | y += r*0.6; 36 | let a = -τ/6; 37 | let [c, s] = [Math.cos(a)*r*1.5, Math.sin(a)*r*1.5]; 38 | let [p, q] = [x + c, y + s]; 39 | 40 | // Draw the dial and shaft. 41 | args.painter.trace(trace => { 42 | trace.ctx.arc(x, y, r, τ/2, τ); 43 | trace.line(x, y, p, q); 44 | }).thenStroke('black'); 45 | // Draw the indicator head. 46 | args.painter.trace(trace => trace.arrowHead(p, q, r*0.3, a, τ/4)).thenFill('black'); 47 | } 48 | 49 | let MeasurementGate = new GateBuilder(). 50 | setSerializedIdAndSymbol("Measure"). 51 | setTitle("Measurement Gate"). 52 | setBlurb("Measures whether a qubit is ON or OFF, without conditioning on the result."). 53 | promiseHasNoNetEffectOnStateVector(). // Because in the simulation we defer measurement by preventing operations. 54 | setDrawer(drawMeasurementGate). 55 | setExtraDisableReasonFinder(args => { 56 | if (args.isNested) { 57 | return "can't\nnest\nmeasure\n(sorry)"; 58 | } 59 | let isMeasured = (args.measuredMask & (1<= r) { 34 | return out_id; 35 | } 36 | float d = read_input_A(); 37 | d *= factor; 38 | d = floor(mod(d + 0.5, r)); 39 | return floor(mod(out_id + r - d + 0.5, r)); 40 | `); 41 | 42 | ModularAdditionGates.PlusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 43 | setSerializedId("+AmodR" + span). 44 | setSymbol("+A\nmod R"). 45 | setTitle("Modular Addition Gate"). 46 | setBlurb("Adds input A into the target, mod input R.\nOnly affects values below R."). 47 | setRequiredContextKeys("Input Range A", "Input Range R"). 48 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 49 | setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( 50 | ...ketArgs(ctx, span, ['A', 'R']), 51 | WglArg.float("factor", +1))). 52 | setKnownEffectToParametrizedPermutation((t, a, r) => t < r ? (t + a) % r : t)); 53 | 54 | ModularAdditionGates.MinusAModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 55 | setAlternateFromFamily(ModularAdditionGates.PlusAModRFamily). 56 | setSerializedId("-AmodR" + span). 57 | setSymbol("−A\nmod R"). 58 | setTitle("Modular Subtraction Gate"). 59 | setBlurb("Subtracts input A out of the target, mod input R.\nOnly affects values below R."). 60 | setRequiredContextKeys("Input Range A", "Input Range R"). 61 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 62 | setActualEffectToShaderProvider(ctx => MODULAR_ADDITION_SHADER.withArgs( 63 | ...ketArgs(ctx, span, ['A', 'R']), 64 | WglArg.float("factor", -1))). 65 | setKnownEffectToParametrizedPermutation((t, a, r) => t < r ? Util.properMod(t - a, r) : t)); 66 | 67 | ModularAdditionGates.all = [ 68 | ...ModularAdditionGates.PlusAModRFamily.all, 69 | ...ModularAdditionGates.MinusAModRFamily.all, 70 | ]; 71 | 72 | export {ModularAdditionGates} 73 | -------------------------------------------------------------------------------- /src/gates/ModularIncrementGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 19 | import {Util} from "../base/Util.js" 20 | import {WglArg} from "../webgl/WglArg.js" 21 | 22 | let ModularIncrementGates = {}; 23 | 24 | /** 25 | * @param {!string} inputKey 26 | * @param {!int} span 27 | * @param {!string=} modName 28 | * @returns {!function(!GateCheckArgs) : (undefined|!string)} 29 | */ 30 | let modulusTooBigChecker = (inputKey, span, modName='mod') => args => { 31 | let r = args.context.get('Input Range ' + inputKey); 32 | let d = args.context.get('Input Default ' + inputKey); 33 | if (r !== undefined && r.length > span) { 34 | return `${modName}\ntoo\nbig`; 35 | } 36 | if (r === undefined && d !== undefined && d > 1<= r 50 | ? out_id 51 | // HACK: sometimes mod(value-equal-to-r, r) returns r instead of 0. The perturbation works around it. 52 | : floor(mod(out_id + r - amount, r - 0.000001));`); 53 | 54 | ModularIncrementGates.IncrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 55 | setSerializedId("incmodR" + span). 56 | setSymbol("+1\nmod R"). 57 | setTitle("Modular Increment Gate"). 58 | setBlurb("Adds 1 into the target, but wraps R-1 to 0.\n" + 59 | "Only affects values less than R."). 60 | setRequiredContextKeys("Input Range R"). 61 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 62 | setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( 63 | ...ketArgs(ctx, span, ['R']), 64 | WglArg.float("amount", +1))). 65 | setKnownEffectToParametrizedPermutation((t, a) => t < a ? (t + 1) % a : t)); 66 | 67 | ModularIncrementGates.DecrementModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 68 | setAlternateFromFamily(ModularIncrementGates.IncrementModRFamily). 69 | setSerializedId("decmodR" + span). 70 | setSymbol("−1\nmod R"). 71 | setTitle("Modular Decrement Gate"). 72 | setBlurb("Subtracts 1 out of the target, but wraps 0 to R-1.\n" + 73 | "Only affects values less than R."). 74 | setRequiredContextKeys("Input Range R"). 75 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 76 | setActualEffectToShaderProvider(ctx => MODULAR_INCREMENT_SHADER.withArgs( 77 | ...ketArgs(ctx, span, ['R']), 78 | WglArg.float("amount", -1))). 79 | setKnownEffectToParametrizedPermutation((t, a) => t < a ? Util.properMod(t - 1, a) : t)); 80 | 81 | ModularIncrementGates.all = [ 82 | ...ModularIncrementGates.IncrementModRFamily.all, 83 | ...ModularIncrementGates.DecrementModRFamily.all, 84 | ]; 85 | 86 | export {ModularIncrementGates, modulusTooBigChecker} 87 | -------------------------------------------------------------------------------- /src/gates/ModularMultiplyAccumulateGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {BIG_MUL_MOD_SHADER_CODE} from "./MultiplyAccumulateGates.js" 18 | import {Gate} from "../circuit/Gate.js" 19 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 20 | import {modulusTooBigChecker} from "./ModularIncrementGates.js" 21 | import {Util} from "../base/Util.js" 22 | import {WglArg} from "../webgl/WglArg.js" 23 | 24 | let ModularMultiplyAccumulateGates = {}; 25 | 26 | const MODULAR_MULTIPLY_ACCUMULATE_SHADER = ketShaderPermute( 27 | ` 28 | uniform float factor; 29 | ${ketInputGateShaderCode('A')} 30 | ${ketInputGateShaderCode('B')} 31 | ${ketInputGateShaderCode('R')} 32 | ${BIG_MUL_MOD_SHADER_CODE} 33 | `, 34 | ` 35 | float r = read_input_R(); 36 | float a = read_input_A(); 37 | float b = read_input_B(); 38 | 39 | float d = big_mul_mod(factor * a, b, r); 40 | 41 | float in_id = floor(mod(out_id - d + 0.5, r)); 42 | if (in_id < 0.0) { 43 | in_id += r; 44 | } 45 | if (in_id >= r) { 46 | in_id -= r; 47 | } 48 | 49 | return out_id >= r ? out_id : in_id; 50 | `); 51 | 52 | ModularMultiplyAccumulateGates.PlusABModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 53 | setSerializedId("+ABmodR" + span). 54 | setSymbol("+AB\nmod R"). 55 | setTitle("Modular Multiply-Add Gate"). 56 | setBlurb("Adds input A times input B into the target, mod input R.\nOnly affects values below R."). 57 | setRequiredContextKeys("Input Range A", "Input Range B", "Input Range R"). 58 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 59 | setActualEffectToShaderProvider(ctx => MODULAR_MULTIPLY_ACCUMULATE_SHADER.withArgs( 60 | ...ketArgs(ctx, span, ['A', 'B', 'R']), 61 | WglArg.float("factor", +1))). 62 | setKnownEffectToParametrizedPermutation((t, a, b, r) => t < r ? (t + a*b) % r : t)); 63 | 64 | ModularMultiplyAccumulateGates.MinusABModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 65 | setAlternateFromFamily(ModularMultiplyAccumulateGates.PlusABModRFamily). 66 | setSerializedId("-ABmodR" + span). 67 | setSymbol("−AB\nmod R"). 68 | setTitle("Modular Multiply-Subtract Gate"). 69 | setBlurb("Subtracts input A times input B out of the target, mod input R.\nOnly affects values below R."). 70 | setRequiredContextKeys("Input Range A", "Input Range B", "Input Range R"). 71 | setExtraDisableReasonFinder(modulusTooBigChecker("R", span)). 72 | setActualEffectToShaderProvider(ctx => MODULAR_MULTIPLY_ACCUMULATE_SHADER.withArgs( 73 | ...ketArgs(ctx, span, ['A', 'B', 'R']), 74 | WglArg.float("factor", -1))). 75 | setKnownEffectToParametrizedPermutation((t, a, b, r) => t < r ? Util.properMod(t - a*b, r) : t)); 76 | 77 | ModularMultiplyAccumulateGates.all = [ 78 | ...ModularMultiplyAccumulateGates.PlusABModRFamily.all, 79 | ...ModularMultiplyAccumulateGates.MinusABModRFamily.all, 80 | ]; 81 | 82 | export {ModularMultiplyAccumulateGates} 83 | -------------------------------------------------------------------------------- /src/gates/MultiplicationGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 19 | import { 20 | modularMultiply, 21 | modularUnmultiply, 22 | MODULAR_INVERSE_SHADER_CODE 23 | } from "./ModularMultiplicationGates.js" 24 | 25 | let MultiplicationGates = {}; 26 | 27 | const MULTIPLICATION_SHADER = ketShaderPermute( 28 | ` 29 | ${MODULAR_INVERSE_SHADER_CODE} 30 | ${ketInputGateShaderCode('A')} 31 | `, 32 | ` 33 | float input_a = read_input_A(); 34 | input_a = mod(input_a, span); 35 | float v = modular_multiplicative_inverse(input_a, span); 36 | if (v == -1.0) { 37 | return out_id; 38 | } 39 | return big_mul_mod(out_id, v, span); 40 | `); 41 | 42 | const INVERSE_MULTIPLICATION_SHADER = ketShaderPermute( 43 | ` 44 | ${MODULAR_INVERSE_SHADER_CODE} 45 | ${ketInputGateShaderCode('A')} 46 | `, 47 | ` 48 | float input_a = read_input_A(); 49 | input_a = mod(input_a, span); 50 | if (modular_multiplicative_inverse(input_a, span) == -1.0) { 51 | return out_id; 52 | } 53 | return big_mul_mod(out_id, input_a, span); 54 | `); 55 | 56 | MultiplicationGates.TimesAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 57 | setSerializedId("*A" + span). 58 | setSymbol("×A"). 59 | setTitle("Multiplication Gate"). 60 | setBlurb("Multiplies the target by input A.\n" + 61 | "No effect if the input is even (would be irreversible)."). 62 | setRequiredContextKeys("Input Range A"). 63 | setActualEffectToShaderProvider(ctx => MULTIPLICATION_SHADER.withArgs(...ketArgs(ctx, span, ['A']))). 64 | setKnownEffectToParametrizedPermutation((x, a) => modularMultiply(x, a, 1< builder. 67 | setAlternateFromFamily(MultiplicationGates.TimesAFamily). 68 | setSerializedId("/A" + span). 69 | setSymbol("×A^-1"). 70 | setTitle("Inverse Multiplication Gate"). 71 | setBlurb("Inverse-multiplies the target by input A (modulo 2^n).\n" + 72 | "No effect if the input is even (would be irreversible)."). 73 | setRequiredContextKeys("Input Range A"). 74 | setKnownEffectToParametrizedPermutation((x, a) => modularUnmultiply(x, a, 1< INVERSE_MULTIPLICATION_SHADER.withArgs(...ketArgs(ctx, span, ['A'])))); 76 | 77 | MultiplicationGates.all = [ 78 | ...MultiplicationGates.TimesAFamily.all, 79 | ...MultiplicationGates.TimesAInverseFamily.all, 80 | ]; 81 | 82 | export { 83 | MultiplicationGates, 84 | MODULAR_INVERSE_SHADER_CODE 85 | } 86 | -------------------------------------------------------------------------------- /src/gates/PivotFlipGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 19 | import {modulusTooBigChecker} from "./ModularIncrementGates.js" 20 | 21 | let PivotFlipGates = {}; 22 | 23 | const PIVOT_FLIP_SHADER = ketShaderPermute( 24 | ` 25 | ${ketInputGateShaderCode('A')} 26 | `, 27 | ` 28 | float a = read_input_A(); 29 | return out_id >= a ? out_id : a - out_id - 1.0; 30 | `); 31 | 32 | PivotFlipGates.FlipUnderA = Gate.buildFamily(1, 16, (span, builder) => builder. 33 | setSerializedId('Flip PIVOT_FLIP_SHADER.withArgs(...ketArgs(ctx, span, ['A']))). 40 | setKnownEffectToParametrizedPermutation((t, a) => t >= a ? t : a - t - 1)); 41 | 42 | PivotFlipGates.all = [ 43 | ...PivotFlipGates.FlipUnderA.all, 44 | ]; 45 | 46 | export {PivotFlipGates} 47 | -------------------------------------------------------------------------------- /src/gates/PoweringGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {GatePainting} from "../draw/GatePainting.js" 19 | import {Matrix} from "../math/Matrix.js" 20 | 21 | let PoweringGates = {}; 22 | 23 | const τ = Math.PI * 2; 24 | const XPow = t => { 25 | let c = Math.cos(τ * t) / 2; 26 | let s = Math.sin(τ * t) / 2; 27 | return new Matrix(2, 2, new Float32Array([0.5+c, s, 0.5-c, -s, 0.5-c, -s, 0.5+c, s])); 28 | }; 29 | const YPow = t => { 30 | let c = Math.cos(τ * t) / 2; 31 | let s = Math.sin(τ * t) / 2; 32 | return new Matrix(2, 2, new Float32Array([0.5+c, s, -s, c-0.5, s, 0.5-c, 0.5+c, s])); 33 | }; 34 | const ZPow = t => { 35 | let c = Math.cos(τ * t); 36 | let s = Math.sin(τ * t); 37 | return new Matrix(2, 2, new Float32Array([1, 0, 0, 0, 0, 0, c, s])); 38 | }; 39 | 40 | PoweringGates.XForward = new GateBuilder(). 41 | setSerializedIdAndSymbol("X^t"). 42 | setTitle("X-Raising Gate (forward)"). 43 | setBlurb("Right-handed cycle from no-op to X."). 44 | setDrawer(GatePainting.makeCycleDrawer(1, 1)). 45 | setEffectToTimeVaryingMatrix(XPow). 46 | promiseEffectIsUnitary(). 47 | gate; 48 | 49 | PoweringGates.XBackward = new GateBuilder(). 50 | setAlternate(PoweringGates.XForward). 51 | setSerializedIdAndSymbol("X^-t"). 52 | setTitle("X-Raising Gate (backward)"). 53 | setBlurb("Left-handed cycle from no-op to X."). 54 | setDrawer(GatePainting.makeCycleDrawer(-1, 1)). 55 | setEffectToTimeVaryingMatrix(t => XPow(-t)). 56 | promiseEffectIsUnitary(). 57 | gate; 58 | 59 | PoweringGates.YForward = new GateBuilder(). 60 | setSerializedIdAndSymbol("Y^t"). 61 | setTitle("Y-Raising Gate (forward)"). 62 | setBlurb("Right-handed cycle from no-op to Y."). 63 | setDrawer(GatePainting.makeCycleDrawer(0.5, 1)). 64 | setEffectToTimeVaryingMatrix(YPow). 65 | promiseEffectIsUnitary(). 66 | gate; 67 | 68 | PoweringGates.YBackward = new GateBuilder(). 69 | setAlternate(PoweringGates.YForward). 70 | setSerializedIdAndSymbol("Y^-t"). 71 | setTitle("Y-Raising Gate (backward)"). 72 | setBlurb("Left-handed cycle from no-op to Y."). 73 | setDrawer(GatePainting.makeCycleDrawer(-0.5, 1)). 74 | setEffectToTimeVaryingMatrix(t => YPow(-t)). 75 | promiseEffectIsUnitary(). 76 | gate; 77 | 78 | PoweringGates.ZForward = new GateBuilder(). 79 | setSerializedIdAndSymbol("Z^t"). 80 | setTitle("Z-Raising Gate (forward)"). 81 | setBlurb("Right-handed cycle from no-op to Z."). 82 | setDrawer(GatePainting.makeCycleDrawer(-1, -0.5)). 83 | setEffectToTimeVaryingMatrix(ZPow). 84 | promiseEffectOnlyPhases(). 85 | gate; 86 | 87 | PoweringGates.ZBackward = new GateBuilder(). 88 | setAlternate(PoweringGates.ZForward). 89 | setSerializedIdAndSymbol("Z^-t"). 90 | setTitle("Z-Raising Gate (backward)"). 91 | setBlurb("Left-handed cycle from no-op to Z."). 92 | setDrawer(GatePainting.makeCycleDrawer(1, -0.5)). 93 | setEffectToTimeVaryingMatrix(t => ZPow(-t)). 94 | promiseEffectOnlyPhases(). 95 | gate; 96 | 97 | PoweringGates.all = [ 98 | PoweringGates.XForward, 99 | PoweringGates.YForward, 100 | PoweringGates.ZForward, 101 | PoweringGates.XBackward, 102 | PoweringGates.YBackward, 103 | PoweringGates.ZBackward 104 | ]; 105 | 106 | export {PoweringGates} 107 | -------------------------------------------------------------------------------- /src/gates/QuarterTurnGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate, GateBuilder} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | 20 | let QuarterTurnGates = {}; 21 | 22 | /** @type {!Gate} */ 23 | QuarterTurnGates.SqrtXForward = new GateBuilder(). 24 | setSerializedIdAndSymbol('X^½'). 25 | setTitle("√X Gate"). 26 | setBlurb("Principle square root of Not."). 27 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0.25, 0, 0)). 28 | gate; 29 | 30 | /** @type {!Gate} */ 31 | QuarterTurnGates.SqrtXBackward = new GateBuilder(). 32 | setAlternate(QuarterTurnGates.SqrtXForward). 33 | setSerializedIdAndSymbol('X^-½'). 34 | setTitle("X^-½ Gate"). 35 | setBlurb("Adjoint square root of Not."). 36 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0.75, 0, 0)). 37 | gate; 38 | 39 | /** @type {!Gate} */ 40 | QuarterTurnGates.SqrtYForward = new GateBuilder(). 41 | setSerializedIdAndSymbol('Y^½'). 42 | setTitle("√Y Gate"). 43 | setBlurb("Principle square root of Y."). 44 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0, 0.25, 0)). 45 | gate; 46 | 47 | /** @type {!Gate} */ 48 | QuarterTurnGates.SqrtYBackward = new GateBuilder(). 49 | setAlternate(QuarterTurnGates.SqrtYForward). 50 | setSerializedIdAndSymbol('Y^-½'). 51 | setTitle("Y^-½ Gate"). 52 | setBlurb("Adjoint square root of Y."). 53 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0, 0.75, 0)). 54 | gate; 55 | 56 | /** @type {!Gate} */ 57 | QuarterTurnGates.SqrtZForward = new GateBuilder(). 58 | setSerializedId('Z^½'). 59 | setSymbol('S'). 60 | setTitle("√Z Gate"). 61 | setBlurb("Principle square root of Z.\nAlso known as the 'S' gate."). 62 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0, 0, 0.25)). 63 | gate; 64 | 65 | /** @type {!Gate} */ 66 | QuarterTurnGates.SqrtZBackward = new GateBuilder(). 67 | setAlternate(QuarterTurnGates.SqrtZForward). 68 | setSerializedId('Z^-½'). 69 | setSymbol('S^-1'). 70 | setTitle("Z^-½ Gate"). 71 | setBlurb("Adjoint square root of Z."). 72 | setKnownEffectToMatrix(Matrix.fromPauliRotation(0, 0, 0.75)). 73 | gate; 74 | 75 | QuarterTurnGates.all = [ 76 | QuarterTurnGates.SqrtXForward, 77 | QuarterTurnGates.SqrtYForward, 78 | QuarterTurnGates.SqrtZForward, 79 | QuarterTurnGates.SqrtXBackward, 80 | QuarterTurnGates.SqrtYBackward, 81 | QuarterTurnGates.SqrtZBackward 82 | ]; 83 | 84 | export {QuarterTurnGates} 85 | -------------------------------------------------------------------------------- /src/gates/ReverseBitsGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {Gate} from "../circuit/Gate.js" 19 | import {ketArgs, ketShaderPermute} from "../circuit/KetShaderUtil.js" 20 | import {Seq} from "../base/Seq.js" 21 | 22 | let _generateReverseShaderForSize = span => span < 2 ? undefined : ketShaderPermute( 23 | '', 24 | ` 25 | float rev = 0.0; 26 | for (int k = 0; k < ${span}; k++) { 27 | rev *= 2.0; 28 | rev += mod(out_id, 2.0); 29 | out_id = floor(out_id*0.5); 30 | } 31 | return rev; 32 | `, 33 | span); 34 | 35 | let reverseShaders = Seq.range(Config.MAX_WIRE_COUNT + 1).map(_generateReverseShaderForSize).toArray(); 36 | 37 | /** 38 | * @param {!int} span 39 | * @returns {!function(!CircuitEvalContext) : !WglConfiguredShader} 40 | */ 41 | let reverseShaderForSize = span => ctx => reverseShaders[span].withArgs(...ketArgs(ctx, span)); 42 | 43 | let ReverseBitsGateFamily = Gate.buildFamily(2, 16, (span, builder) => builder. 44 | setSerializedId("rev" + span). 45 | setSymbol("Reverse"). 46 | setTitle("Reverse Order"). 47 | setBlurb("Swaps bits into the opposite order."). 48 | setKnownEffectToBitPermutation(i => span - 1 - i). 49 | setActualEffectToShaderProvider(reverseShaderForSize(span))); 50 | 51 | export {ReverseBitsGateFamily, reverseShaderForSize} 52 | -------------------------------------------------------------------------------- /src/gates/SpacerGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {GateBuilder} from "../circuit/Gate.js" 19 | import {GatePainting} from "../draw/GatePainting.js" 20 | import {Rect} from "../math/Rect.js" 21 | 22 | let SpacerGate = new GateBuilder(). 23 | setSerializedIdAndSymbol("…"). 24 | setTitle("Spacer"). 25 | setBlurb("A gate with no effect."). 26 | markAsNotInterestedInControls(). 27 | promiseHasNoNetEffectOnStateVector(). 28 | setDrawer(args => { 29 | // Drawn as an ellipsis. 30 | if (args.isInToolbox || args.isHighlighted) { 31 | let backColor = Config.GATE_FILL_COLOR; 32 | if (args.isHighlighted) { 33 | backColor = Config.HIGHLIGHTED_GATE_FILL_COLOR; 34 | } 35 | args.painter.fillRect(args.rect, backColor); 36 | GatePainting.paintOutline(args); 37 | } else { 38 | // Whitespace for the ellipsis. 39 | let {x, y} = args.rect.center(); 40 | let r = new Rect(x - 14, y - 2, 28, 4); 41 | args.painter.fillRect(r, Config.BACKGROUND_COLOR_CIRCUIT); 42 | } 43 | args.painter.fillCircle(args.rect.center().offsetBy(7, 0), 2, "black"); 44 | args.painter.fillCircle(args.rect.center(), 2, "black"); 45 | args.painter.fillCircle(args.rect.center().offsetBy(-7, 0), 2, "black"); 46 | }). 47 | gate; 48 | 49 | export {SpacerGate} 50 | -------------------------------------------------------------------------------- /src/gates/SwapGateHalf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GateBuilder} from "../circuit/Gate.js" 18 | import {GatePainting} from "../draw/GatePainting.js" 19 | import {Matrix} from "../math/Matrix.js" 20 | import {Rect} from "../math/Rect.js" 21 | import {Seq} from "../base/Seq.js" 22 | 23 | // Note: there is special code to handle swaps sprinkled everywhere, since it's the only gate with two paired sides. 24 | 25 | /** @type {!Gate} */ 26 | let SwapGateHalf = new GateBuilder(). 27 | setSerializedIdAndSymbol("Swap"). 28 | setTitle("Swap Gate [Half]"). 29 | setBlurb("Swaps the values of two qubits.\n(Place two in the same column.)"). 30 | setKnownEffectToMatrix(Matrix.square( 31 | 1, 0, 0, 0, 32 | 0, 0, 1, 0, 33 | 0, 1, 0, 0, 34 | 0, 0, 0, 1)). 35 | setDrawer(args => { 36 | if (args.isInToolbox || args.isHighlighted) { 37 | GatePainting.DEFAULT_DRAWER(args); 38 | return; 39 | } 40 | 41 | // A swap gate half is shown as a small X (joined by a line to the other half; that's handled elsewhere). 42 | let swapRect = Rect.centeredSquareWithRadius(args.rect.center(), args.rect.w / 6); 43 | args.painter.strokeLine(swapRect.topLeft(), swapRect.bottomRight()); 44 | args.painter.strokeLine(swapRect.topRight(), swapRect.bottomLeft()); 45 | }). 46 | setExtraDisableReasonFinder(args => { 47 | let col = args.innerColumn; 48 | let swapRows = Seq.range(col.gates.length).filter(row => col.gates[row] === SwapGateHalf); 49 | let n = swapRows.count(); 50 | if (n === 1) { 51 | return "need\nother\nswap"; 52 | } 53 | if (n > 2) { 54 | return "too\nmany\nswap"; 55 | } 56 | 57 | let affectsMeasured = swapRows.any(r => (args.measuredMask & (1 << r)) !== 0); 58 | let affectsUnmeasured = swapRows.any(r => (args.measuredMask & (1 << r)) === 0); 59 | if (affectsMeasured && col.hasCoherentControl(args.measuredMask)) { 60 | return "no\nremix\n(sorry)"; 61 | } 62 | if (affectsMeasured && affectsUnmeasured && col.hasControl()) { 63 | return "no\nremix\n(sorry)"; 64 | } 65 | 66 | return undefined; 67 | }). 68 | gate; 69 | 70 | export {SwapGateHalf} 71 | -------------------------------------------------------------------------------- /src/gates/VariousXGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | 20 | let VariousXGates = {}; 21 | 22 | VariousXGates.X3 = Gate.fromKnownMatrix( 23 | "X^⅓", 24 | Matrix.fromPauliRotation(1 / 6, 0, 0), 25 | "X^⅓ Gate", 26 | "Principle third root of X."); 27 | VariousXGates.X3i = Gate.fromKnownMatrix( 28 | "X^-⅓", 29 | Matrix.fromPauliRotation(-1 / 6, 0, 0), 30 | "X^-⅓ Gate", 31 | "Adjoint third root of X.", 32 | undefined, 33 | VariousXGates.X3); 34 | VariousXGates.X4 = Gate.fromKnownMatrix( 35 | "X^¼", 36 | Matrix.fromPauliRotation(1 / 8, 0, 0), 37 | "X^¼ Gate", 38 | "Principle fourth root of X."); 39 | VariousXGates.X4i = Gate.fromKnownMatrix( 40 | "X^-¼", 41 | Matrix.fromPauliRotation(-1 / 8, 0, 0), 42 | "X^-¼ Gate", 43 | "Adjoint fourth root of X.", 44 | undefined, 45 | VariousXGates.X4); 46 | VariousXGates.X8 = Gate.fromKnownMatrix( 47 | "X^⅛", 48 | Matrix.fromPauliRotation(1 / 16, 0, 0), 49 | "X^⅛ Gate", 50 | "Principle eighth root of X."); 51 | VariousXGates.X8i = Gate.fromKnownMatrix( 52 | "X^-⅛", 53 | Matrix.fromPauliRotation(-1 / 16, 0, 0), 54 | "X^-⅛ Gate", 55 | "Adjoint eighth root of X.", 56 | undefined, 57 | VariousXGates.X8); 58 | VariousXGates.X16 = Gate.fromKnownMatrix( 59 | "X^⅟₁₆", 60 | Matrix.fromPauliRotation(1 / 32, 0, 0), 61 | "X^⅟₁₆ Gate", 62 | "Principle sixteenth root of X."); 63 | VariousXGates.X16i = Gate.fromKnownMatrix( 64 | "X^-⅟₁₆", 65 | Matrix.fromPauliRotation(-1 / 32, 0, 0), 66 | "X^-⅟₁₆ Gate", 67 | "Adjoint sixteenth root of X.", 68 | undefined, 69 | VariousXGates.X16); 70 | VariousXGates.X32 = Gate.fromKnownMatrix( 71 | "X^⅟₃₂", 72 | Matrix.fromPauliRotation(1 / 64, 0, 0), 73 | "X^⅟₃₂ Gate", 74 | "Principle 32'nd root of X."); 75 | VariousXGates.X32i = Gate.fromKnownMatrix( 76 | "X^-⅟₃₂", 77 | Matrix.fromPauliRotation(-1 / 64, 0, 0), 78 | "X^-⅟₃₂ Gate", 79 | "Adjoint 32'nd root of X.", 80 | undefined, 81 | VariousXGates.X32); 82 | 83 | VariousXGates.all =[ 84 | VariousXGates.X3, 85 | VariousXGates.X4, 86 | VariousXGates.X8, 87 | VariousXGates.X16, 88 | VariousXGates.X32, 89 | VariousXGates.X3i, 90 | VariousXGates.X4i, 91 | VariousXGates.X8i, 92 | VariousXGates.X16i, 93 | VariousXGates.X32i, 94 | ]; 95 | 96 | export {VariousXGates} 97 | -------------------------------------------------------------------------------- /src/gates/VariousYGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | 20 | let VariousYGates = {}; 21 | 22 | VariousYGates.Y3 = Gate.fromKnownMatrix( 23 | "Y^⅓", 24 | Matrix.fromPauliRotation(0, 1 / 6, 0), 25 | "Y^⅓ Gate", 26 | "Principle third root of Y."); 27 | VariousYGates.Y3i = Gate.fromKnownMatrix( 28 | "Y^-⅓", 29 | Matrix.fromPauliRotation(0, -1 / 6, 0), 30 | "Y^-⅓ Gate", 31 | "Adjoint third root of Y.", 32 | undefined, 33 | VariousYGates.Y3); 34 | VariousYGates.Y4 = Gate.fromKnownMatrix( 35 | "Y^¼", 36 | Matrix.fromPauliRotation(0, 1 / 8, 0), 37 | "Y^¼ Gate", 38 | "Principle fourth root of Y."); 39 | VariousYGates.Y4i = Gate.fromKnownMatrix( 40 | "Y^-¼", 41 | Matrix.fromPauliRotation(0, -1 / 8, 0), 42 | "Y^-¼ Gate", 43 | "Adjoint fourth root of Y.", 44 | undefined, 45 | VariousYGates.Y4); 46 | VariousYGates.Y8 = Gate.fromKnownMatrix( 47 | "Y^⅛", 48 | Matrix.fromPauliRotation(0, 1 / 16, 0), 49 | "Y^⅛ Gate", 50 | "Principle eighth root of Y."); 51 | VariousYGates.Y8i = Gate.fromKnownMatrix( 52 | "Y^-⅛", 53 | Matrix.fromPauliRotation(0, -1 / 16, 0), 54 | "Y^-⅛ Gate", 55 | "Adjoint eighth root of Y.", 56 | undefined, 57 | VariousYGates.Y8); 58 | VariousYGates.Y16 = Gate.fromKnownMatrix( 59 | "Y^⅟₁₆", 60 | Matrix.fromPauliRotation(0, 1 / 32, 0), 61 | "Y^⅟₁₆ Gate", 62 | "Principle sixteenth root of Y."); 63 | VariousYGates.Y16i = Gate.fromKnownMatrix( 64 | "Y^-⅟₁₆", 65 | Matrix.fromPauliRotation(0, -1 / 32, 0), 66 | "Y^-⅟₁₆ Gate", 67 | "Adjoint sixteenth root of Y.", 68 | undefined, 69 | VariousYGates.Y16); 70 | VariousYGates.Y32 = Gate.fromKnownMatrix( 71 | "Y^⅟₃₂", 72 | Matrix.fromPauliRotation(0, 1 / 64, 0), 73 | "Y^⅟₃₂ Gate", 74 | "Principle 32'nd root of Y."); 75 | VariousYGates.Y32i = Gate.fromKnownMatrix( 76 | "Y^-⅟₃₂", 77 | Matrix.fromPauliRotation(0, -1 / 64, 0), 78 | "Y^-⅟₃₂ Gate", 79 | "Adjoint 32'nd root of Y.", 80 | undefined, 81 | VariousYGates.Y32); 82 | 83 | VariousYGates.all =[ 84 | VariousYGates.Y3, 85 | VariousYGates.Y4, 86 | VariousYGates.Y8, 87 | VariousYGates.Y16, 88 | VariousYGates.Y32, 89 | VariousYGates.Y3i, 90 | VariousYGates.Y4i, 91 | VariousYGates.Y8i, 92 | VariousYGates.Y16i, 93 | VariousYGates.Y32i 94 | ]; 95 | 96 | export {VariousYGates} 97 | -------------------------------------------------------------------------------- /src/gates/VariousZGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Gate} from "../circuit/Gate.js" 18 | import {Matrix} from "../math/Matrix.js" 19 | 20 | let VariousZGates = {}; 21 | 22 | VariousZGates.Z3 = Gate.fromKnownMatrix( 23 | "Z^⅓", 24 | Matrix.fromPauliRotation(0, 0, 1 / 6), 25 | "Z^⅓ Gate", 26 | "Principle third root of Z."); 27 | VariousZGates.Z3i = Gate.fromKnownMatrix( 28 | "Z^-⅓", 29 | Matrix.fromPauliRotation(0, 0, -1 / 6), 30 | "Z^-⅓ Gate", 31 | "Adjoint third root of Z.", 32 | undefined, 33 | VariousZGates.Z3); 34 | VariousZGates.Z4 = Gate.fromKnownMatrix( 35 | "T", 36 | Matrix.fromPauliRotation(0, 0, 1 / 8), 37 | "Z^¼ Gate", 38 | "Principle fourth root of Z.", 39 | "Z^¼"); 40 | VariousZGates.Z4i = Gate.fromKnownMatrix( 41 | "T^-1", 42 | Matrix.fromPauliRotation(0, 0, -1 / 8), 43 | "Z^-¼ Gate", 44 | "Adjoint fourth root of Z.", 45 | "Z^-¼", 46 | VariousZGates.Z4); 47 | VariousZGates.Z8 = Gate.fromKnownMatrix( 48 | "Z^⅛", 49 | Matrix.fromPauliRotation(0, 0, 1 / 16), 50 | "Z^⅛ Gate", 51 | "Principle eighth root of Z."); 52 | VariousZGates.Z8i = Gate.fromKnownMatrix( 53 | "Z^-⅛", 54 | Matrix.fromPauliRotation(0, 0, -1 / 16), 55 | "Z^-⅛ Gate", 56 | "Adjoint eighth root of Z.", 57 | undefined, 58 | VariousZGates.Z8); 59 | VariousZGates.Z16 = Gate.fromKnownMatrix( 60 | "Z^⅟₁₆", 61 | Matrix.fromPauliRotation(0, 0, 1 / 32), 62 | "Z^⅟₁₆ Gate", 63 | "Principle 16'th root of Z."); 64 | VariousZGates.Z16i = Gate.fromKnownMatrix( 65 | "Z^-⅟₁₆", 66 | Matrix.fromPauliRotation(0, 0, -1 / 32), 67 | "Z^-⅟₁₆ Gate", 68 | "Adjoint 16'th root of Z.", 69 | undefined, 70 | VariousZGates.Z16); 71 | 72 | VariousZGates.Z32 = Gate.fromKnownMatrix( 73 | "Z^⅟₃₂", 74 | Matrix.fromPauliRotation(0, 0, 1 / 64), 75 | "Z^⅟₃₂ Gate", 76 | "Principle 32'nd root of Z."); 77 | VariousZGates.Z64 = Gate.fromKnownMatrix( 78 | "Z^⅟₆₄", 79 | Matrix.fromPauliRotation(0, 0, 1 / 128), 80 | "Z^⅟₆₄ Gate", 81 | "Principle 64'th root of Z."); 82 | VariousZGates.Z128 = Gate.fromKnownMatrix( 83 | "Z^⅟₁₂₈", 84 | Matrix.fromPauliRotation(0, 0, 1 / 256), 85 | "Z^⅟₁₂₈ Gate", 86 | "Principle 128'th root of Z."); 87 | 88 | VariousZGates.all =[ 89 | VariousZGates.Z3, 90 | VariousZGates.Z4, 91 | VariousZGates.Z8, 92 | VariousZGates.Z16, 93 | VariousZGates.Z32, 94 | VariousZGates.Z64, 95 | VariousZGates.Z128, 96 | VariousZGates.Z3i, 97 | VariousZGates.Z4i, 98 | VariousZGates.Z8i, 99 | VariousZGates.Z16i 100 | ]; 101 | 102 | export {VariousZGates} 103 | -------------------------------------------------------------------------------- /src/gates/XorGates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {Gate} from "../circuit/Gate.js" 19 | import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "../circuit/KetShaderUtil.js" 20 | 21 | let XorGates = {}; 22 | 23 | const XOR_SHADER = ketShaderPermute( 24 | ketInputGateShaderCode('A'), 25 | ` 26 | float srcMask = mod(read_input_A(), span); 27 | float bitPos = 1.0; 28 | float result = 0.0; 29 | for (int i = 0; i < ${Config.MAX_WIRE_COUNT}; i++) { 30 | float srcBit = mod(floor(srcMask/bitPos), 2.0); 31 | float dstBit = mod(floor(out_id/bitPos), 2.0); 32 | result += (dstBit + srcBit - dstBit * srcBit * 2.0) * bitPos; 33 | bitPos *= 2.0; 34 | } 35 | return result;`); 36 | 37 | XorGates.XorAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. 38 | setSerializedId("^=A" + span). 39 | setSymbol("⊕A"). 40 | setTitle("Xor Gate [input A]"). 41 | setBlurb("Xors input A into the qubits covered by this gate."). 42 | setRequiredContextKeys("Input Range A"). 43 | setKnownEffectToParametrizedPermutation((t, a) => t ^ (a & ((1< XOR_SHADER.withArgs(...ketArgs(ctx, span, ['A'])))); 45 | 46 | XorGates.all = [ 47 | ...XorGates.XorAFamily.all, 48 | ]; 49 | 50 | export {XorGates} 51 | -------------------------------------------------------------------------------- /src/issues.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {notifyAboutKnownIssue} from "./fallback.js" 18 | 19 | let canvasCreatedForTesting = document.createElement('canvas'); 20 | let webglContextCreatedForTesting = canvasCreatedForTesting.getContext('webgl') || 21 | canvasCreatedForTesting.getContext('experimental-webgl'); 22 | 23 | /** @returns {!boolean} */ 24 | function detectWebGlNotSupported() { 25 | return webglContextCreatedForTesting === null || webglContextCreatedForTesting === undefined; 26 | } 27 | 28 | function doDetectIssues() { 29 | if (detectWebGlNotSupported()) { 30 | notifyAboutKnownIssue( 31 | "Can't simulate circuits. Your browser doesn't support WebGL, or has it disabled.", 32 | "https://github.com/Strilanc/Quirk/issues/168", 33 | [/Computing circuit values failed/, /Error creating WebGL context./]) 34 | } 35 | } 36 | 37 | export {doDetectIssues, canvasCreatedForTesting, webglContextCreatedForTesting} 38 | -------------------------------------------------------------------------------- /src/math/Point.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * A two dimensional point with real coordinates. 19 | */ 20 | class Point { 21 | /** 22 | * @param {!number} x The new point's x coordinate. 23 | * @param {!number} y The new point's y coordinate. 24 | */ 25 | constructor(x, y) { 26 | /** 27 | * The point's x coordinate. 28 | * @type {!number} 29 | */ 30 | this.x = x; 31 | /** 32 | * The point's y coordinate. 33 | * @member Point#y 34 | * @type {!number} 35 | */ 36 | this.y = y; 37 | } 38 | 39 | /** 40 | * Determines if the given value is a point with the same coordinates as the receiving point. 41 | * @param {!Point|*} obj The point, or other value, to compare against. 42 | * @returns {!boolean} 43 | */ 44 | isEqualTo(obj) { 45 | if (!(obj instanceof Point)) { 46 | return false; 47 | } 48 | /** @type {!Point} */ 49 | let other = obj; 50 | return other.x === this.x && other.y === this.y; 51 | } 52 | 53 | /** 54 | * @returns {!string} 55 | */ 56 | toString() { 57 | return `(x: ${this.x}, y: ${this.y})`; 58 | } 59 | 60 | /** 61 | * Returns the result of adding the receiving point's coordinates to the given offset values. 62 | * @param {!number} dx The x offset. 63 | * @param {!number} dy The y offset. 64 | * @returns {!Point} 65 | */ 66 | offsetBy(dx, dy) { 67 | return new Point(this.x + dx, this.y + dy); 68 | } 69 | 70 | /** 71 | * Returns the result of pairing and adding the receiving point's, and the given point's, coordinates. 72 | * @param {!Point} p 73 | * @returns {!Point} 74 | */ 75 | plus(p) { 76 | return new Point(this.x + p.x, this.y + p.y); 77 | } 78 | 79 | /** 80 | * Returns the result of subtracting the given point's coordinates from the receiving point. 81 | * @param {!Point} p 82 | * @returns {!Point} 83 | */ 84 | minus(p) { 85 | return new Point(this.x - p.x, this.y - p.y); 86 | } 87 | 88 | /** 89 | * Returns the result of scaling the receiving point's coordinates by the given factor. 90 | * @param {!number} c The scaling factor. 91 | * @returns {!Point} 92 | */ 93 | times(c) { 94 | return new Point(this.x * c, this.y * c); 95 | } 96 | 97 | /** 98 | * Returns the Euclidean distance between the receiving point and the given point. 99 | * @param {!Point} other 100 | * @returns {!number} 101 | */ 102 | distanceTo(other) { 103 | let dx = this.x - other.x; 104 | let dy = this.y - other.y; 105 | return Math.sqrt(dx*dx + dy*dy); 106 | } 107 | } 108 | 109 | export {Point} 110 | -------------------------------------------------------------------------------- /src/ui/clear.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @param {!Revision} revision 19 | * @param {!Observable.} obsIsAnyOverlayShowing 20 | */ 21 | function initClear(revision, obsIsAnyOverlayShowing) { 22 | const EMPTY_STATE = '{"cols":[]}'; 23 | 24 | const clearAllButton = /** @type {!HTMLButtonElement} */ document.getElementById('clear-all-button'); 25 | revision.latestActiveCommit().zipLatest(obsIsAnyOverlayShowing, (r, v) => ({r, v})).subscribe(({r, v}) => { 26 | clearAllButton.disabled = r === EMPTY_STATE || v; 27 | }); 28 | clearAllButton.addEventListener('click', () => revision.commit(EMPTY_STATE)); 29 | 30 | const clearCircuitButton = /** @type {!HTMLButtonElement} */ document.getElementById('clear-circuit-button'); 31 | revision.latestActiveCommit().zipLatest(obsIsAnyOverlayShowing, (r, v) => ({r, v})).subscribe(({r, v}) => { 32 | clearCircuitButton.disabled = r === _getEmptyCircuitState(revision) || v; 33 | }); 34 | clearCircuitButton.addEventListener('click', () => revision.commit(_getEmptyCircuitState(revision))); 35 | } 36 | 37 | /** 38 | * Returns current state without circuit. Keeps all custom gates. 39 | * @param {!Revision} revision 40 | * @returns {!string} 41 | */ 42 | function _getEmptyCircuitState(revision) { 43 | let val = JSON.parse(revision.peekActiveCommit()); 44 | val["cols"] = []; 45 | 46 | return JSON.stringify(val); 47 | } 48 | 49 | export {initClear} 50 | -------------------------------------------------------------------------------- /src/ui/sim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {CircuitDefinition} from "../circuit/CircuitDefinition.js" 18 | import {Config} from "../Config.js" 19 | import {CircuitStats} from "../circuit/CircuitStats.js" 20 | 21 | const getCircuitCycleTime = (() => { 22 | /** 23 | * Milliseconds. 24 | * @type {!number} 25 | */ 26 | let _circuitCycleTime = 0; 27 | /** 28 | * Milliseconds. 29 | * @type {!number} 30 | */ 31 | let _prevRealTime = performance.now(); 32 | 33 | return () => { 34 | let nextRealTime = performance.now(); 35 | let elapsed = (nextRealTime - _prevRealTime) / Config.CYCLE_DURATION_MS; 36 | _circuitCycleTime += elapsed; 37 | _circuitCycleTime %= 1; 38 | _prevRealTime = nextRealTime; 39 | return _circuitCycleTime; 40 | }; 41 | })(); 42 | 43 | /** @type {undefined|!CircuitStats} */ 44 | let _cachedStats = undefined; 45 | 46 | /** 47 | * @param {!CircuitDefinition} circuit 48 | * @returns {!CircuitStats} 49 | */ 50 | function simulate(circuit) { 51 | if (_cachedStats !== undefined && _cachedStats.circuitDefinition.isEqualTo(circuit)) { 52 | return _cachedStats.withTime(getCircuitCycleTime()); 53 | } 54 | 55 | _cachedStats = undefined; 56 | let result = CircuitStats.fromCircuitAtTime(circuit, getCircuitCycleTime()); 57 | if (circuit.stableDuration() === Infinity) { 58 | _cachedStats = result; 59 | } 60 | return result; 61 | } 62 | 63 | export {simulate, getCircuitCycleTime} 64 | -------------------------------------------------------------------------------- /src/ui/title.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Config} from "../Config.js" 18 | import {fromJsonText_CircuitDefinition} from "../circuit/Serializer.js" 19 | 20 | /** 21 | * @param {!Revision} revision 22 | */ 23 | function initTitleSync(revision) { 24 | const titleForState = jsonText => { 25 | //noinspection UnusedCatchParameterJS,EmptyCatchBlockJS 26 | try { 27 | let circuitDef = fromJsonText_CircuitDefinition(jsonText); 28 | if (!circuitDef.isEmpty()) { 29 | return `Quirk: ${circuitDef.readableHash()}`; 30 | } 31 | } catch (_) { 32 | } 33 | return Config.EMPTY_CIRCUIT_TITLE; 34 | }; 35 | 36 | revision.latestActiveCommit().subscribe(jsonText => { 37 | // Add a slight delay, so that history changes use the old title. 38 | setTimeout(() => { document.title = titleForState(jsonText); }, 0); 39 | }); 40 | } 41 | 42 | export {initTitleSync} 43 | -------------------------------------------------------------------------------- /src/ui/undo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @param {!Revision} revision 19 | * @param {!Observable.} obsIsAnyOverlayShowing 20 | */ 21 | function initUndoRedo(revision, obsIsAnyOverlayShowing) { 22 | const overlay_divs = [ 23 | document.getElementById('gate-forge-div'), 24 | document.getElementById('export-div') 25 | ]; 26 | 27 | const undoButton = /** @type {!HTMLButtonElement} */ document.getElementById('undo-button'); 28 | const redoButton = /** @type {!HTMLButtonElement} */ document.getElementById('redo-button'); 29 | revision.latestActiveCommit().zipLatest(obsIsAnyOverlayShowing, (_, b) => b).subscribe(anyShowing => { 30 | undoButton.disabled = revision.isAtBeginningOfHistory() || anyShowing; 31 | redoButton.disabled = revision.isAtEndOfHistory() || anyShowing; 32 | }); 33 | 34 | undoButton.addEventListener('click', () => revision.undo()); 35 | redoButton.addEventListener('click', () => revision.redo()); 36 | 37 | document.addEventListener("keydown", e => { 38 | // Don't capture keystrokes while menus are showing. 39 | for (let div of overlay_divs) { 40 | if (div.style.display !== 'NONE' && div.style.display !== 'none') { 41 | return; 42 | } 43 | } 44 | 45 | const Y_KEY = 89; 46 | const Z_KEY = 90; 47 | let isUndo = e.keyCode === Z_KEY && e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; 48 | let isRedo1 = e.keyCode === Z_KEY && e.ctrlKey && e.shiftKey && !e.altKey && !e.metaKey; 49 | let isRedo2 = e.keyCode === Y_KEY && e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; 50 | if (isUndo) { 51 | revision.undo(); 52 | e.preventDefault(); 53 | } 54 | if (isRedo1 || isRedo2) { 55 | revision.redo(); 56 | e.preventDefault(); 57 | } 58 | }); 59 | } 60 | 61 | export {initUndoRedo} 62 | -------------------------------------------------------------------------------- /src/ui/url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {notifyAboutRecoveryFromUnexpectedError} from "../fallback.js" 18 | import {CircuitDefinition} from "../circuit/CircuitDefinition.js" 19 | import {Config} from "../Config.js" 20 | import {HistoryPusher} from "../browser/HistoryPusher.js" 21 | import {fromJsonText_CircuitDefinition, Serializer} from "../circuit/Serializer.js" 22 | 23 | function urlWithCircuitHash(jsonText) { 24 | if (jsonText.indexOf('%') !== -1 || jsonText.indexOf('&') !== -1) { 25 | jsonText = encodeURIComponent(jsonText); 26 | } 27 | return "#" + Config.URL_CIRCUIT_PARAM_KEY + "=" + jsonText; 28 | } 29 | 30 | /** 31 | * @param {!Revision} revision 32 | */ 33 | function initUrlCircuitSync(revision) { 34 | // Pull initial circuit out of URL '#x=y' arguments. 35 | const getHashParameters = () => { 36 | let hashText = document.location.hash.substr(1); 37 | let paramsMap = new Map(); 38 | if (hashText !== "") { 39 | for (let keyVal of hashText.split("&")) { 40 | let eq = keyVal.indexOf("="); 41 | if (eq === -1) { 42 | continue; 43 | } 44 | let key = keyVal.substring(0, eq); 45 | let val = decodeURIComponent(keyVal.substring(eq + 1)); 46 | paramsMap.set(key, val); 47 | } 48 | } 49 | return paramsMap; 50 | }; 51 | 52 | const historyPusher = new HistoryPusher(); 53 | const loadCircuitFromUrl = () => { 54 | try { 55 | historyPusher.currentStateIsMemorableButUnknown(); 56 | let params = getHashParameters(); 57 | if (!params.has(Config.URL_CIRCUIT_PARAM_KEY)) { 58 | let def = document.DEFAULT_CIRCUIT || JSON.stringify(Serializer.toJson(CircuitDefinition.EMPTY)); 59 | params.set(Config.URL_CIRCUIT_PARAM_KEY, def); 60 | } 61 | 62 | let jsonText = params.get(Config.URL_CIRCUIT_PARAM_KEY); 63 | historyPusher.currentStateIsMemorableAndEqualTo(jsonText); 64 | let circuitDef = fromJsonText_CircuitDefinition(jsonText); 65 | let cleanedJson = JSON.stringify(Serializer.toJson(circuitDef)); 66 | revision.clear(cleanedJson); 67 | if (circuitDef.isEmpty() && params.size === 1) { 68 | historyPusher.currentStateIsNotMemorable(); 69 | } else { 70 | let urlHash = urlWithCircuitHash(jsonText); 71 | historyPusher.stateChange(jsonText, urlHash); 72 | } 73 | } catch (ex) { 74 | notifyAboutRecoveryFromUnexpectedError( 75 | "Defaulted to an empty circuit. Failed to understand circuit from URL.", 76 | {document_location_hash: document.location.hash}, 77 | ex); 78 | } 79 | }; 80 | 81 | window.addEventListener('popstate', loadCircuitFromUrl); 82 | loadCircuitFromUrl(); 83 | 84 | revision.latestActiveCommit().whenDifferent().skip(1).subscribe(jsonText => { 85 | historyPusher.stateChange(jsonText, urlWithCircuitHash(jsonText)); 86 | }); 87 | } 88 | 89 | export {initUrlCircuitSync} 90 | -------------------------------------------------------------------------------- /src/webgl/WglMortalValueSlot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * A place for a value associated with a webgl context, that needs to be re-initialized when the context is lost. 19 | * @template T 20 | */ 21 | class WglMortalValueSlot { 22 | /** 23 | * @param {!function() : T} initializer 24 | * @param {!function(T) : void} deinitializer 25 | * @template T 26 | */ 27 | constructor(initializer, deinitializer) { 28 | /** 29 | * @type {!(function(): T)} 30 | * @template T 31 | */ 32 | this.initializer = initializer; 33 | /** 34 | * @type {!(function(T): void)} 35 | * @template T 36 | */ 37 | this.deinitializer = deinitializer; 38 | /** 39 | * @type {undefined|!int} 40 | * @private 41 | */ 42 | this.lifetimeId = undefined; 43 | /** 44 | * @type {undefined|T} 45 | * @template T 46 | * @private 47 | */ 48 | this.mortalValue = undefined; 49 | } 50 | 51 | /** 52 | * Returns the mortal value stored in the slot, initializing or re-initializing it if necessary. 53 | * @param {!int} lifetimeCounter 54 | * @returns T 55 | */ 56 | initializedValue(lifetimeCounter) { 57 | if (this.lifetimeId !== lifetimeCounter) { 58 | this.ensureDeinitialized(); 59 | this.mortalValue = this.initializer(); 60 | this.lifetimeId = lifetimeCounter; 61 | } 62 | 63 | return this.mortalValue; 64 | } 65 | 66 | /** 67 | * Initializes or re-initializes the stored mortal value, if necessary. 68 | * @param {!int} lifetimeCounter 69 | */ 70 | ensureInitialized(lifetimeCounter) { 71 | this.initializedValue(lifetimeCounter); 72 | } 73 | 74 | /** 75 | * Cleans up the stored mortal value, if necessary. 76 | */ 77 | ensureDeinitialized() { 78 | if (this.lifetimeId !== undefined) { 79 | let val = this.mortalValue; 80 | this.lifetimeId = undefined; 81 | this.mortalValue = undefined; 82 | this.deinitializer(val); 83 | } 84 | } 85 | } 86 | 87 | export {WglMortalValueSlot} 88 | -------------------------------------------------------------------------------- /test/base/DetailedError.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {DetailedError} from "../../src/base/DetailedError.js" 19 | 20 | let suite = new Suite("DetailedError"); 21 | 22 | class ReentrantDescription { 23 | toString() { 24 | return new DetailedError("re-enter", this).details; 25 | } 26 | } 27 | 28 | suite.test("re-entrant_details", () => { 29 | assertThat(new DetailedError("test", new ReentrantDescription()).details). 30 | isEqualTo("(failed to describe detailsObj due to possibly re-entrancy)"); 31 | }); 32 | -------------------------------------------------------------------------------- /test/base/RestartableRng.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {RestartableRng} from "../../src/base/RestartableRng.js" 19 | 20 | let suite = new Suite("RestartableRng"); 21 | 22 | suite.test("pre-repeat_multiple-copies", () => { 23 | let rng1 = new RestartableRng(); 24 | let v1 = rng1.random(); 25 | let v2 = rng1.random(); 26 | 27 | let rng2 = rng1.restarted(); 28 | assertThat(rng2.random()).isEqualTo(v1); 29 | assertThat(rng2.random()).isEqualTo(v2); 30 | 31 | let rng3 = rng2.restarted(); 32 | assertThat(rng3.random()).isEqualTo(v1); 33 | assertThat(rng3.random()).isEqualTo(v2); 34 | 35 | let rng4 = rng1.restarted(); 36 | assertThat(rng4.random()).isEqualTo(v1); 37 | assertThat(rng4.random()).isEqualTo(v2); 38 | }); 39 | 40 | suite.test("post-repeat", () => { 41 | let rng1 = new RestartableRng(); 42 | let rng2 = rng1.restarted(); 43 | let v1 = rng1.random(); 44 | assertThat(rng2.random()).isEqualTo(v1); 45 | }); 46 | 47 | suite.test("reverse-repeat", () => { 48 | let rng1 = new RestartableRng(); 49 | let rng2 = rng1.restarted(); 50 | let v1 = rng2.random(); 51 | assertThat(rng1.random()).isEqualTo(v1); 52 | }); 53 | -------------------------------------------------------------------------------- /test/circuit/Controls.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {assertTrue, assertFalse, assertThat, assertThrows, Suite} from "../TestUtil.js" 18 | import {Controls} from "../../src/circuit/Controls.js" 19 | 20 | let suite = new Suite("Controls"); 21 | 22 | suite.test("isEqualTo", () => { 23 | let s = new Controls(0xF, 0xE); 24 | assertTrue(s.isEqualTo(s)); 25 | assertFalse(s.isEqualTo("")); 26 | assertFalse(s.isEqualTo(null)); 27 | 28 | assertThat(s.desiredValueMask).isEqualTo(0xE); 29 | assertThat(s.inclusionMask).isEqualTo(0xF); 30 | assertTrue(s.isEqualTo(new Controls(0xF, 0xE))); 31 | assertFalse(s.isEqualTo(new Controls(0, 0))); 32 | assertFalse(s.isEqualTo(new Controls(0xF, 0xF))); 33 | assertFalse(s.isEqualTo(new Controls(0xE, 0xE))); 34 | assertTrue(new Controls(0x3, 0x2).isEqualTo(new Controls(0x3, 0x2))); 35 | assertTrue(Controls.NONE.isEqualTo(new Controls(0, 0))); 36 | }); 37 | 38 | suite.test("allowsState", () => { 39 | assertTrue(Controls.NONE.allowsState(0)); 40 | assertTrue(Controls.NONE.allowsState(1)); 41 | 42 | let m = new Controls(0x5, 0x1); 43 | assertFalse(m.allowsState(0)); 44 | assertTrue(m.allowsState(1)); 45 | assertFalse(m.allowsState(2)); 46 | assertTrue(m.allowsState(3)); 47 | assertFalse(m.allowsState(4)); 48 | assertFalse(m.allowsState(5)); 49 | assertFalse(m.allowsState(6)); 50 | assertFalse(m.allowsState(7)); 51 | assertFalse(m.allowsState(8)); 52 | assertTrue(m.allowsState(9)); 53 | }); 54 | 55 | suite.test("desiredValueFor", () => { 56 | assertThat(Controls.NONE.desiredValueFor(0)).isEqualTo(undefined); 57 | assertThat(Controls.NONE.desiredValueFor(1)).isEqualTo(undefined); 58 | 59 | let m = new Controls(0x5, 0x1); 60 | assertThat(m.desiredValueFor(0)).isEqualTo(true); 61 | assertThat(m.desiredValueFor(1)).isEqualTo(undefined); 62 | assertThat(m.desiredValueFor(2)).isEqualTo(false); 63 | assertThat(m.desiredValueFor(3)).isEqualTo(undefined); 64 | }); 65 | 66 | suite.test("bit", () => { 67 | assertThat(Controls.bit(0, true)).isEqualTo(new Controls(0x1, 0x1)); 68 | assertThat(Controls.bit(0, false)).isEqualTo(new Controls(0x1, 0x0)); 69 | assertThat(Controls.bit(2, true)).isEqualTo(new Controls(0x4, 0x4)); 70 | assertThat(Controls.bit(2, false)).isEqualTo(new Controls(0x4, 0x0)); 71 | }); 72 | 73 | suite.test("and", () => { 74 | assertThat(Controls.NONE.and(Controls.NONE)).isEqualTo(Controls.NONE); 75 | assertThat(Controls.NONE.desiredValueFor(1)).isEqualTo(undefined); 76 | 77 | let m = new Controls(0x5, 0x1); 78 | assertThat(Controls.bit(0, true).and(Controls.bit(2, false))).isEqualTo(m); 79 | assertThat(Controls.bit(2, false).and(Controls.bit(0, true))).isEqualTo(m); 80 | assertThat(Controls.NONE.and(m)).isEqualTo(m); 81 | assertThat(m.and(m)).isEqualTo(m); 82 | 83 | assertThrows(() => Controls.bit(0, true).and(Controls.bit(0, false))); 84 | }); 85 | 86 | suite.test("toString", () => { 87 | assertTrue(typeof(Controls.NONE.toString()) === "string"); 88 | assertTrue(typeof(new Controls(0x5, 0x1).toString()) === "string"); 89 | }); 90 | -------------------------------------------------------------------------------- /test/circuit/Gate.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {Gate, GateBuilder} from "../../src/circuit/Gate.js" 19 | 20 | import {Matrix} from "../../src/math/Matrix.js" 21 | 22 | let suite = new Suite("Gate"); 23 | 24 | suite.test("toString_runsWithoutFailing", () => { 25 | let g = new GateBuilder().setEffectToTimeVaryingMatrix(_ => Matrix.HADAMARD).gate; 26 | assertThat(g.toString()).isNotEqualTo(null); 27 | }); 28 | 29 | suite.test("stableDuration", () => { 30 | let m0 = Gate.fromKnownMatrix("symbol", Matrix.HADAMARD, "name", "blurb"); 31 | let mt = new GateBuilder().setEffectToTimeVaryingMatrix(t => Matrix.square(t, 0, 0, 0)).gate; 32 | 33 | assertThat(m0.stableDuration()).isEqualTo(Infinity); 34 | assertThat(mt.stableDuration()).isEqualTo(0); 35 | }); 36 | 37 | suite.test("knownMatrixAt", () => { 38 | let m0 = Gate.fromKnownMatrix("symbol", Matrix.HADAMARD, "name", "blurb"); 39 | let mt = new GateBuilder().setEffectToTimeVaryingMatrix(t => Matrix.square(t, 0, 0, 0)).gate; 40 | 41 | assertThat(m0.knownMatrixAt(0)).isEqualTo(Matrix.HADAMARD); 42 | assertThat(m0.knownMatrixAt(0.5)).isEqualTo(Matrix.HADAMARD); 43 | 44 | assertThat(mt.knownMatrixAt(0)).isEqualTo(Matrix.square(0, 0, 0, 0)); 45 | assertThat(mt.knownMatrixAt(0.5)).isEqualTo(Matrix.square(0.5, 0, 0, 0)); 46 | }); 47 | -------------------------------------------------------------------------------- /test/circuit/GateColumn.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat, assertTrue, assertFalse} from "../TestUtil.js" 18 | import {GateColumn} from "../../src/circuit/GateColumn.js" 19 | 20 | import {Gates} from "../../src/gates/AllGates.js" 21 | 22 | let suite = new Suite("GateColumn"); 23 | 24 | suite.test("isEqualTo", () => { 25 | // Trivial case: 26 | assertThat(GateColumn.empty(1)).isEqualTo(GateColumn.empty(1)); 27 | assertThat(GateColumn.empty(2)).isNotEqualTo(GateColumn.empty(1)); 28 | 29 | // Equivalence groups: 30 | let groups = [ 31 | [GateColumn.empty(0), GateColumn.empty(0), new GateColumn([]), new GateColumn([])], 32 | [GateColumn.empty(1), GateColumn.empty(1), new GateColumn([undefined]), new GateColumn([undefined])], 33 | [GateColumn.empty(2), GateColumn.empty(2), new GateColumn([undefined, undefined]), 34 | new GateColumn([undefined, undefined])], 35 | [new GateColumn([Gates.HalfTurns.X]), new GateColumn([Gates.HalfTurns.X])], 36 | [new GateColumn([Gates.Controls.Control]), new GateColumn([Gates.Controls.Control])], 37 | [new GateColumn([Gates.HalfTurns.X, undefined]), new GateColumn([Gates.HalfTurns.X, undefined])], 38 | [new GateColumn([undefined, Gates.HalfTurns.X]), new GateColumn([undefined, Gates.HalfTurns.X])] 39 | ]; 40 | for (let g1 of groups) { 41 | for (let g2 of groups) { 42 | for (let e1 of g1) { 43 | for (let e2 of g2) { 44 | if (g1 === g2) { 45 | assertThat(e1).isEqualTo(e2); 46 | assertTrue(e1.isEqualTo(e2)); 47 | } else { 48 | assertThat(e1).isNotEqualTo(e2); 49 | assertFalse(e1.isEqualTo(e2)); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | }); 56 | 57 | suite.test("isEmpty", () => { 58 | assertTrue(GateColumn.empty(0).isEmpty()); 59 | assertTrue(GateColumn.empty(1).isEmpty()); 60 | assertTrue(GateColumn.empty(2).isEmpty()); 61 | assertTrue(GateColumn.empty(10).isEmpty()); 62 | assertTrue(new GateColumn([]).isEmpty()); 63 | assertTrue(new GateColumn([undefined]).isEmpty()); 64 | assertTrue(new GateColumn([undefined, undefined]).isEmpty()); 65 | assertFalse(new GateColumn([Gates.Controls.Control]).isEmpty()); 66 | assertFalse(new GateColumn([Gates.Special.SwapHalf]).isEmpty()); 67 | assertFalse(new GateColumn([Gates.HalfTurns.X]).isEmpty()); 68 | assertFalse(new GateColumn([Gates.HalfTurns.X, undefined]).isEmpty()); 69 | assertFalse(new GateColumn([Gates.HalfTurns.X, Gates.HalfTurns.X]).isEmpty()); 70 | }); 71 | -------------------------------------------------------------------------------- /test/circuit/GateShaders.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {GateShaders} from "../../src/circuit/GateShaders.js" 19 | import {assertThatCircuitUpdateActsLikeMatrix} from "../CircuitOperationTestUtil.js" 20 | 21 | import {Complex} from "../../src/math/Complex.js" 22 | import {Seq} from "../../src/base/Seq.js" 23 | import {Shaders} from "../../src/webgl/Shaders.js" 24 | import {Matrix} from "../../src/math/Matrix.js" 25 | 26 | let suite = new Suite("GateShaders"); 27 | 28 | suite.testUsingWebGL('cycleAllBits', () => { 29 | let inp = Shaders.vec2Data(Seq.range(16).flatMap(e => [e*4 + 1, e*4 + 2]).toFloat32Array()).toVec2Texture(4); 30 | let actual = GateShaders.cycleAllBits(inp, -1).readVec2Outputs(4); 31 | assertThat(actual).isEqualTo(new Float32Array([ 32 | 1, 2, 9,10, 17,18, 25,26, 33 | 33,34, 41,42, 49,50, 57,58, 34 | 5, 6, 13,14, 21,22, 29,30, 35 | 37,38, 45,46, 53,54, 61,62 36 | ])); 37 | inp.deallocByDepositingInPool(); 38 | }); 39 | 40 | suite.testUsingWebGL("matrixOperation", () => { 41 | let repeats = 3; 42 | for (let size = 1; size < 5; size++) { 43 | let d = 1< new Complex(Math.random() - 0.5, Math.random() - 0.5)); 45 | assertThatCircuitUpdateActsLikeMatrix( 46 | ctx => GateShaders.applyMatrixOperation(ctx, matrix), 47 | matrix, 48 | repeats); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /test/circuit/KetShaderUtil.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {ketArgs, ketShader, ketShaderPermute, ketShaderPhase} from "../../src/circuit/KetShaderUtil.js" 19 | import {assertThatCircuitShaderActsLikeMatrix} from "../CircuitOperationTestUtil.js" 20 | import {Complex} from "../../src/math/Complex.js" 21 | import {Matrix} from "../../src/math/Matrix.js" 22 | import {WglArg} from "../../src/webgl/WglArg.js" 23 | 24 | let suite = new Suite("KetShaderUtil"); 25 | 26 | suite.testUsingWebGL("ketShader", () => { 27 | let shader = ketShader( 28 | 'uniform vec2 a, b, c, d;', 29 | 'return cmul(inp(0.0), a+(c-a)*out_id) + cmul(inp(1.0), b+(d-b)*out_id);', 30 | 1); 31 | assertThatCircuitShaderActsLikeMatrix( 32 | ctx => shader.withArgs( 33 | ...ketArgs(ctx), 34 | WglArg.vec2("a", 2, 3), 35 | WglArg.vec2("b", 5, 7), 36 | WglArg.vec2("c", 11, 13), 37 | WglArg.vec2("d", 17, 19)), 38 | new Matrix(2, 2, new Float32Array([2, 3, 5, 7, 11, 13, 17, 19]))); 39 | }); 40 | 41 | suite.testUsingWebGL("ketShaderPermute", () => { 42 | let shader = ketShaderPermute( 43 | '', 44 | 'return mod(out_id + 1.0, 4.0);', 45 | 2); 46 | assertThatCircuitShaderActsLikeMatrix( 47 | ctx => shader.withArgs(...ketArgs(ctx)), 48 | Matrix.generateTransition(4, i => (i - 1) & 3)); 49 | }); 50 | 51 | suite.testUsingWebGL("ketShaderPhase", () => { 52 | let shader = ketShaderPhase( 53 | '', 54 | 'return out_id/10.0;', 55 | 3); 56 | assertThatCircuitShaderActsLikeMatrix( 57 | ctx => shader.withArgs(...ketArgs(ctx)), 58 | Matrix.generateDiagonal(8, i => Complex.polar(1, i/10))); 59 | }); 60 | -------------------------------------------------------------------------------- /test/gates/ArithmeticGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {ArithmeticGates} from "../../src/gates/ArithmeticGates.js" 19 | import {InputGates} from "../../src/gates/InputGates.js" 20 | import { 21 | assertThatCircuitUpdateActsLikeMatrix, 22 | assertThatGateActsLikePermutation, 23 | } from "../CircuitOperationTestUtil.js" 24 | import {advanceStateWithCircuit} from "../../src/circuit/CircuitComputeUtil.js" 25 | 26 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 27 | import {GateColumn} from "../../src/circuit/GateColumn.js" 28 | import {Matrix} from "../../src/math/Matrix.js" 29 | 30 | let suite = new Suite("ArithmeticGates"); 31 | 32 | suite.testUsingWebGL('plus_A', () => { 33 | assertThatCircuitUpdateActsLikeMatrix( 34 | ctx => advanceStateWithCircuit( 35 | ctx, 36 | new CircuitDefinition(4, [new GateColumn([ 37 | ArithmeticGates.PlusAFamily.ofSize(2), undefined, InputGates.InputAFamily.ofSize(2), undefined])]), 38 | false), 39 | Matrix.generateTransition(16, i => { 40 | let a = (i >> 2) & 3; 41 | let t = i & 3; 42 | return (a<<2) | (t+a)&3; 43 | })); 44 | }); 45 | 46 | suite.testUsingWebGL('minus_A', () => { 47 | assertThatCircuitUpdateActsLikeMatrix( 48 | ctx => advanceStateWithCircuit( 49 | ctx, 50 | new CircuitDefinition(4, [new GateColumn([ 51 | InputGates.InputAFamily.ofSize(2), undefined, ArithmeticGates.MinusAFamily.ofSize(2), undefined])]), 52 | false), 53 | Matrix.generateTransition(16, i => { 54 | let a = i & 3; 55 | let t = (i >> 2) & 3; 56 | return a | (((t-a)&3)<<2); 57 | })); 58 | }); 59 | 60 | suite.testUsingWebGL('plus_minus_A_like_permutation', () => { 61 | assertThatGateActsLikePermutation( 62 | ArithmeticGates.PlusAFamily.ofSize(3), 63 | (t, a) => (t + a) & 7, 64 | [2]); 65 | 66 | assertThatGateActsLikePermutation( 67 | ArithmeticGates.MinusAFamily.ofSize(3), 68 | (t, a) => (t - a) & 7, 69 | [4]); 70 | }); 71 | -------------------------------------------------------------------------------- /test/gates/BitCountGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {BitCountGates} from "../../src/gates/BitCountGates.js" 19 | import {InputGates} from "../../src/gates/InputGates.js" 20 | import {assertThatCircuitUpdateActsLikeMatrix} from "../CircuitOperationTestUtil.js" 21 | import {advanceStateWithCircuit} from "../../src/circuit/CircuitComputeUtil.js" 22 | 23 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 24 | import {Matrix} from "../../src/math/Matrix.js" 25 | import {Util} from "../../src/base/Util.js" 26 | 27 | let suite = new Suite("BitCountGates"); 28 | 29 | let GATE_SET = new Map([ 30 | ['A', InputGates.InputAFamily], 31 | ['-', undefined], 32 | ['/', null], 33 | ['P', BitCountGates.PlusBitCountAFamily], 34 | ['M', BitCountGates.MinusBitCountAFamily] 35 | ]); 36 | 37 | suite.testUsingWebGL('PlusBitCountA', () => { 38 | assertThatCircuitUpdateActsLikeMatrix( 39 | ctx => advanceStateWithCircuit( 40 | ctx, 41 | CircuitDefinition.fromTextDiagram(GATE_SET, 42 | `-A- 43 | -/- 44 | -/- 45 | -P- 46 | -/-`), 47 | false), 48 | Matrix.generateTransition(1<<5, i => { 49 | let a = i & 7; 50 | let t = (i >> 3) & 3; 51 | t += Util.numberOfSetBits(a); 52 | t &= 3; 53 | return a | (t << 3); 54 | })); 55 | }); 56 | 57 | suite.testUsingWebGL('MinusBitCountA', () => { 58 | assertThatCircuitUpdateActsLikeMatrix( 59 | ctx => advanceStateWithCircuit( 60 | ctx, 61 | CircuitDefinition.fromTextDiagram(GATE_SET, 62 | `-A- 63 | -/- 64 | -/- 65 | -M- 66 | -/-`), 67 | false), 68 | Matrix.generateTransition(1<<5, i => { 69 | let a = i & 7; 70 | let t = (i >> 3) & 3; 71 | t -= Util.numberOfSetBits(a); 72 | t &= 3; 73 | return a | (t << 3); 74 | })); 75 | }); 76 | -------------------------------------------------------------------------------- /test/gates/CycleBitsGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {assertThatCircuitShaderActsLikeMatrix} from "../CircuitOperationTestUtil.js" 19 | import {cycleBitsShader} from "../../src/gates/CycleBitsGates.js" 20 | 21 | import {Matrix} from "../../src/math/Matrix.js" 22 | 23 | let suite = new Suite("CycleBitsGates"); 24 | 25 | suite.testUsingWebGL('cycleBitsShader', () => { 26 | assertThatCircuitShaderActsLikeMatrix( 27 | ctx => cycleBitsShader(ctx, 3, 2), 28 | Matrix.generateTransition(8, i => ((i&1)<<2) | ((i>>1)&3))); 29 | assertThatCircuitShaderActsLikeMatrix( 30 | ctx => cycleBitsShader(ctx, 4, -2), 31 | Matrix.generateTransition(16, i => ((i&3)<<2) | ((i>>2)&3))); 32 | }); 33 | -------------------------------------------------------------------------------- /test/gates/DensityMatrixDisplay.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {amplitudesToCouplings} from "../../src/gates/DensityMatrixDisplay.js" 19 | import {Shaders} from "../../src/webgl/Shaders.js" 20 | 21 | let suite = new Suite("DensityMatrixDisplay"); 22 | 23 | suite.testUsingWebGL("amplitudesToCouplings", () => { 24 | let s = Math.sqrt(0.5); 25 | let inp = Shaders.vec2Data(new Float32Array([ 26 | s,0, 27 | 0,0, 28 | 0,0, 29 | s,0 30 | ])).toVec2Texture(2); 31 | 32 | assertThat(amplitudesToCouplings(inp, 1).readVec2Outputs(3)).isApproximatelyEqualTo(new Float32Array([ 33 | 0.5,0, 0,0, 34 | 0, 0, 0,0, 35 | 36 | 0, 0, 0,0, 37 | 0, 0, 0.5,0 38 | ])); 39 | assertThat(amplitudesToCouplings(inp, 2).readVec2Outputs(4)).isApproximatelyEqualTo(new Float32Array([ 40 | 0.5,0, 0,0, 0,0, 0.5,0, 41 | 0,0, 0,0, 0,0, 0,0, 42 | 0,0, 0,0, 0,0, 0,0, 43 | 0.5,0, 0,0, 0,0, 0.5,0 44 | ])); 45 | 46 | inp.deallocByDepositingInPool(); 47 | }); 48 | -------------------------------------------------------------------------------- /test/gates/ExponentiatingGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {Gates} from "../../src/gates/AllGates.js" 19 | import {Complex} from "../../src/math/Complex.js" 20 | import {Matrix} from "../../src/math/Matrix.js" 21 | 22 | let suite = new Suite("ExponentiatingGates"); 23 | 24 | suite.test("timeBased_matchUnoptimized", () => { 25 | let matches = (gate, func) => { 26 | for (let t = 0; t < 1; t += 0.05) { 27 | assertThat(gate.knownMatrixAt(t)).isApproximatelyEqualTo(func(t), 0.0000001); 28 | } 29 | }; 30 | 31 | let i = Complex.I; 32 | let τ = Math.PI * 2; 33 | matches( 34 | Gates.Exponentiating.XForward, 35 | t => Matrix.PAULI_X.liftApply(c => c.times(τ * -t).times(i).exp())); 36 | matches( 37 | Gates.Exponentiating.XBackward, 38 | t => Matrix.PAULI_X.liftApply(c => c.times(τ * t).times(i).exp())); 39 | matches( 40 | Gates.Exponentiating.YForward, 41 | t => Matrix.PAULI_Y.liftApply(c => c.times(τ * -t).times(i).exp())); 42 | matches( 43 | Gates.Exponentiating.YBackward, 44 | t => Matrix.PAULI_Y.liftApply(c => c.times(τ * t).times(i).exp())); 45 | matches( 46 | Gates.Exponentiating.ZForward, 47 | t => Matrix.PAULI_Z.liftApply(c => c.times(τ * -t).times(i).exp())); 48 | matches( 49 | Gates.Exponentiating.ZBackward, 50 | t => Matrix.PAULI_Z.liftApply(c => c.times(τ * t).times(i).exp())); 51 | 52 | matches( 53 | Gates.Powering.XForward, 54 | t => Matrix.PAULI_X.liftApply(c => c.raisedTo(t * 2))); 55 | matches( 56 | Gates.Powering.XBackward, 57 | t => Matrix.PAULI_X.liftApply(c => c.raisedTo(-t * 2))); 58 | matches( 59 | Gates.Powering.YForward, 60 | t => Matrix.PAULI_Y.liftApply(c => c.raisedTo(t * 2))); 61 | matches( 62 | Gates.Powering.YBackward, 63 | t => Matrix.PAULI_Y.liftApply(c => c.raisedTo(-t * 2))); 64 | matches( 65 | Gates.Powering.ZForward, 66 | t => Matrix.PAULI_Z.liftApply(c => c.raisedTo(t * 2))); 67 | matches( 68 | Gates.Powering.ZBackward, 69 | t => Matrix.PAULI_Z.liftApply(c => c.raisedTo(-t * 2))); 70 | }); 71 | -------------------------------------------------------------------------------- /test/gates/FourierTransformGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {assertThatCircuitUpdateActsLikeMatrix} from "../CircuitOperationTestUtil.js" 19 | import {applyControlledPhaseGradient, FourierTransformGates} from "../../src/gates/FourierTransformGates.js" 20 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 21 | import {GateColumn} from "../../src/circuit/GateColumn.js" 22 | import {advanceStateWithCircuit} from "../../src/circuit/CircuitComputeUtil.js" 23 | 24 | import {Complex} from "../../src/math/Complex.js" 25 | import {Matrix} from "../../src/math/Matrix.js" 26 | 27 | let suite = new Suite("FourierTransformGates"); 28 | 29 | suite.testUsingWebGL('controlledPhaseGradient', () => { 30 | assertThatCircuitUpdateActsLikeMatrix( 31 | ctx => applyControlledPhaseGradient(ctx, 3, 1), 32 | Matrix.generateDiagonal(8, i => i < 4 ? 1 : Complex.polar(1, (i-4)*Math.PI/4))); 33 | 34 | assertThatCircuitUpdateActsLikeMatrix( 35 | ctx => applyControlledPhaseGradient(ctx, 4, -1), 36 | Matrix.generateDiagonal(16, i => i < 8 ? 1 : Complex.polar(1, -(i-8)*Math.PI/8))); 37 | }); 38 | 39 | suite.testUsingWebGL('fourierTransform', () => { 40 | assertThatCircuitUpdateActsLikeMatrix( 41 | ctx => advanceStateWithCircuit( 42 | ctx, 43 | new CircuitDefinition(2, [new GateColumn([ 44 | FourierTransformGates.FourierTransformFamily.ofSize(2), undefined])]), 45 | false).output, 46 | Matrix.generate(4, 4, (i, j) => Complex.polar(0.5, i*j*Math.PI/2))); 47 | 48 | assertThatCircuitUpdateActsLikeMatrix( 49 | ctx => advanceStateWithCircuit( 50 | ctx, 51 | new CircuitDefinition(3, [new GateColumn([ 52 | FourierTransformGates.InverseFourierTransformFamily.ofSize(3), undefined, undefined])]), 53 | false).output, 54 | Matrix.generate(8, 8, (i, j) => Complex.polar(Math.sqrt(1/8), -i*j*Math.PI/4))); 55 | }); 56 | -------------------------------------------------------------------------------- /test/gates/Impossible_UniversalNotGate.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {CircuitEvalContext} from "../../src/circuit/CircuitEvalContext.js" 19 | import {CircuitShaders} from "../../src/circuit/CircuitShaders.js" 20 | import {universalNot} from "../../src/gates/Impossible_UniversalNotGate.js" 21 | 22 | import {Controls} from "../../src/circuit/Controls.js" 23 | import {Shaders} from "../../src/webgl/Shaders.js" 24 | import {WglTextureTrader} from "../../src/webgl/WglTextureTrader.js" 25 | 26 | let suite = new Suite("Impossible_UniverseNotGate"); 27 | 28 | suite.testUsingWebGL('universalNot', () => { 29 | let input = Shaders.vec2Data(new Float32Array([ 30 | 1,2, 3,4, 31 | 5,6, 7,8 32 | ])).toVec2Texture(2); 33 | let assertAbout = (index, control) => { 34 | let controlTex = CircuitShaders.controlMask(control).toBoolTexture(2); 35 | let trader = new WglTextureTrader(input); 36 | trader.dontDeallocCurrentTexture(); 37 | let ctx = new CircuitEvalContext( 38 | 0, 39 | index, 40 | 2, 41 | control, 42 | controlTex, 43 | control, 44 | trader, 45 | new Map()); 46 | try { 47 | return assertThat(universalNot(ctx).readVec2Outputs(2)); 48 | } finally { 49 | controlTex.deallocByDepositingInPool(); 50 | } 51 | }; 52 | assertAbout(0, Controls.NONE).isEqualTo(new Float32Array([ 53 | 3,-4, -1,2, 54 | 7,-8, -5,6 55 | ])); 56 | assertAbout(1, Controls.NONE).isEqualTo(new Float32Array([ 57 | 5,-6, 7,-8, 58 | -1,2, -3,4 59 | ])); 60 | assertAbout(0, Controls.bit(1, true)).isEqualTo(new Float32Array([ 61 | 1,2, 3,4, 62 | 7,-8, -5,6 63 | ])); 64 | 65 | input.deallocByDepositingInPool(); 66 | }); 67 | -------------------------------------------------------------------------------- /test/gates/IncrementGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {offsetShader, IncrementGates} from "../../src/gates/IncrementGates.js" 19 | import { 20 | assertThatCircuitShaderActsLikePermutation, 21 | assertThatGateActsLikePermutation, 22 | } from "../CircuitOperationTestUtil.js" 23 | 24 | import {ketArgs} from "../../src/circuit/KetShaderUtil.js" 25 | import {WglArg} from "../../src/webgl/WglArg.js" 26 | 27 | let suite = new Suite("ArithmeticGates"); 28 | 29 | suite.testUsingWebGL('offsetShader', () => { 30 | assertThatCircuitShaderActsLikePermutation( 31 | 3, 32 | ctx => offsetShader.withArgs(...ketArgs(ctx, 3), WglArg.float("amount", 5)), 33 | e => (e+5) & 7); 34 | 35 | assertThatCircuitShaderActsLikePermutation( 36 | 6, 37 | ctx => offsetShader.withArgs(...ketArgs(ctx, 6), WglArg.float("amount", -31)), 38 | e => (e-31) & 63); 39 | }); 40 | 41 | suite.testUsingWebGL('IncrementGate', () => { 42 | assertThatGateActsLikePermutation( 43 | IncrementGates.IncrementFamily.ofSize(3), 44 | e => (e + 1) & 7); 45 | 46 | assertThatGateActsLikePermutation( 47 | IncrementGates.DecrementFamily.ofSize(4), 48 | e => (e - 1) & 15); 49 | }); 50 | -------------------------------------------------------------------------------- /test/gates/InputGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {assertThat, Suite} from "../TestUtil.js" 18 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 19 | import {CircuitStats} from "../../src/circuit/CircuitStats.js" 20 | import {Gates} from "../../src/gates/AllGates.js" 21 | import {Seq} from "../../src/base/Seq.js" 22 | import {Util} from "../../src/base/Util.js" 23 | 24 | let suite = new Suite("InputGates"); 25 | 26 | const TEST_GATES = new Map([ 27 | ['$', Gates.ModularIncrementGates.DecrementModRFamily], 28 | ['*', Gates.MultiplyAccumulateGates.MultiplyAddInputsFamily], 29 | ['X', Gates.HalfTurns.X], 30 | ['⊕', Gates.XorGates.XorAFamily], 31 | ['A', Gates.InputGates.InputAFamily], 32 | ['B', Gates.InputGates.InputBFamily], 33 | ['R', Gates.InputGates.InputRFamily], 34 | ['∀', Gates.InputGates.InputRevAFamily], 35 | ['ᗺ', Gates.InputGates.InputRevBFamily], 36 | ['-', undefined], 37 | ['/', null], 38 | ]); 39 | const circuit = (diagram, ...extraGates) => CircuitDefinition.fromTextDiagram( 40 | Util.mergeMaps(TEST_GATES, new Map(extraGates)), 41 | diagram); 42 | 43 | suite.testUsingWebGL('endianness', () => { 44 | let output = diagram => { 45 | let stats = CircuitStats.fromCircuitAtTime(circuit(diagram), 0); 46 | return Seq.range(stats.finalState.height()). 47 | filter(i => stats.finalState.cell(0, i).isEqualTo(1)). 48 | first(); 49 | }; 50 | 51 | assertThat(output(`-X-A- 52 | ---/- 53 | ---/- 54 | ----- 55 | ---⊕- 56 | ---/- 57 | ---/-`)).isEqualTo(0b0010001); 58 | 59 | assertThat(output(`-X-∀- 60 | ---/- 61 | ---/- 62 | ----- 63 | ---⊕- 64 | ---/- 65 | ---/-`)).isEqualTo(0b1000001); 66 | 67 | assertThat(output(`---$- 68 | ---/- 69 | ---/- 70 | ---/- 71 | -X-R- 72 | -X-/- 73 | ---/- 74 | -X-/-`)).isEqualTo(0b10111010); 75 | 76 | assertThat(output(`---*- 77 | ---/- 78 | -X-A- 79 | -X-B- 80 | ---/-`)).isEqualTo(0b01101); 81 | 82 | assertThat(output(`---*- 83 | ---/- 84 | -X-A- 85 | -X-ᗺ- 86 | ---/-`)).isEqualTo(0b01110); 87 | }); 88 | -------------------------------------------------------------------------------- /test/gates/ModularAdditionGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {assertThatGateActsLikePermutation, assertThatCircuitOutputsBasisKet} from "../CircuitOperationTestUtil.js" 19 | 20 | import {ModularAdditionGates} from "../../src/gates/ModularAdditionGates.js" 21 | import {InputGates} from "../../src/gates/InputGates.js" 22 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 23 | import {Util} from "../../src/base/Util.js" 24 | 25 | let suite = new Suite("ModularAdditionGates"); 26 | 27 | suite.testUsingWebGL('plus_A_mod_R_permutation', () => { 28 | assertThatGateActsLikePermutation( 29 | ModularAdditionGates.PlusAModRFamily.ofSize(2), 30 | (t, a, b) => t < b ? (t + a) % b : t, 31 | [2, 2]); 32 | 33 | assertThatGateActsLikePermutation( 34 | ModularAdditionGates.PlusAModRFamily.ofSize(3), 35 | (t, a, b) => t < b ? (t + a) % b : t, 36 | [1, 2]); 37 | 38 | assertThatGateActsLikePermutation( 39 | ModularAdditionGates.PlusAModRFamily.ofSize(2), 40 | (t, a, b) => t < b ? (t + a) % b : t, 41 | [3, 2]); 42 | }); 43 | 44 | suite.testUsingWebGL('minus_A_mod_R_permutation', () => { 45 | assertThatGateActsLikePermutation( 46 | ModularAdditionGates.MinusAModRFamily.ofSize(2), 47 | (t, a, b) => t < b ? Util.properMod(t - a, b) : t, 48 | [2, 2]); 49 | 50 | assertThatGateActsLikePermutation( 51 | ModularAdditionGates.MinusAModRFamily.ofSize(3), 52 | (t, a, b) => t < b ? Util.properMod(t - a, b) : t, 53 | [1, 2]); 54 | 55 | assertThatGateActsLikePermutation( 56 | ModularAdditionGates.MinusAModRFamily.ofSize(2), 57 | (t, a, b) => t < b ? Util.properMod(t - a, b) : t, 58 | [3, 2]); 59 | }); 60 | 61 | suite.testUsingWebGL('plus_A_mod_R_no_nan', () => { 62 | let circuit = CircuitDefinition.fromTextDiagram(new Map([ 63 | ['a', InputGates.SetA.withParam(0)], 64 | ['r', InputGates.SetR.withParam(33)], 65 | ['p', ModularAdditionGates.PlusAModRFamily], 66 | ['-', undefined], 67 | ['/', null], 68 | ]), `-a-p- 69 | ---/- 70 | -r-/- 71 | ---/- 72 | ---/- 73 | ---/-`); 74 | assertThatCircuitOutputsBasisKet(circuit, 0); 75 | }); 76 | -------------------------------------------------------------------------------- /test/gates/ModularMultiplyAccumulateGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {assertThatGateActsLikePermutation} from "../CircuitOperationTestUtil.js" 19 | 20 | import {ModularMultiplyAccumulateGates} from "../../src/gates/ModularMultiplyAccumulateGates.js" 21 | import {Util} from "../../src/base/Util.js" 22 | 23 | let suite = new Suite("ModularMultiplyAccumulateGates"); 24 | 25 | suite.testUsingWebGL('plus_AB_mod_R_permutation', () => { 26 | assertThatGateActsLikePermutation( 27 | ModularMultiplyAccumulateGates.PlusABModRFamily.ofSize(2), 28 | (t, a, b, r) => t < r ? (t + a*b) % r : t, 29 | [2, 2, 2]); 30 | }); 31 | 32 | suite.testUsingWebGL('minus_AB_mod_R_permutation', () => { 33 | assertThatGateActsLikePermutation( 34 | ModularMultiplyAccumulateGates.MinusABModRFamily.ofSize(2), 35 | (t, a, b, r) => t < r ? Util.properMod(t - a*b, r) : t, 36 | [2, 2, 2]); 37 | }); 38 | -------------------------------------------------------------------------------- /test/gates/MultiplicationGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {Gates} from "../../src/gates/AllGates.js" 19 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 20 | import {modularMultiply, modularUnmultiply} from "../../src/gates/ModularMultiplicationGates.js" 21 | import {assertThatGateActsLikePermutation, assertThatCircuitOutputsBasisKet} from "../CircuitOperationTestUtil.js" 22 | 23 | let suite = new Suite("MultiplicationGates"); 24 | 25 | suite.testUsingWebGL('multiplication_gate', () => { 26 | assertThatGateActsLikePermutation( 27 | Gates.MultiplicationGates.TimesAFamily.ofSize(4), 28 | (x, a) => modularMultiply(x, a, 1<<4), 29 | [4]); 30 | 31 | assertThatGateActsLikePermutation( 32 | Gates.MultiplicationGates.TimesAFamily.ofSize(2), 33 | (x, a) => modularMultiply(x, a, 1<<2), 34 | [4]); 35 | }); 36 | 37 | suite.testUsingWebGL('inverse_multiplication_gate', () => { 38 | assertThatGateActsLikePermutation( 39 | Gates.MultiplicationGates.TimesAInverseFamily.ofSize(4), 40 | (x, a) => modularUnmultiply(x, a, 1<<4), 41 | [4]); 42 | 43 | assertThatGateActsLikePermutation( 44 | Gates.MultiplicationGates.TimesAInverseFamily.ofSize(2), 45 | (x, a) => modularUnmultiply(x, a, 1<<2), 46 | [4]); 47 | }); 48 | 49 | suite.testUsingWebGL('times_big_A', () => { 50 | let circuit = CircuitDefinition.fromTextDiagram(new Map([ 51 | ['a', Gates.InputGates.SetA.withParam(16385)], 52 | ['*', Gates.MultiplicationGates.TimesAFamily], 53 | ['X', Gates.HalfTurns.X], 54 | ['-', undefined], 55 | ['/', null], 56 | ]), `-a-X-*- 57 | -----/- 58 | -----/- 59 | -----/- 60 | -----/- 61 | -----/- 62 | -----/- 63 | -----/- 64 | -----/- 65 | -----/- 66 | -----/- 67 | -----/- 68 | -----/- 69 | ---X-/- 70 | -----/- 71 | -----/-`); 72 | assertThatCircuitOutputsBasisKet(circuit, 24577); 73 | }); 74 | -------------------------------------------------------------------------------- /test/gates/MultiplyAccumulateGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {MultiplyAccumulateGates} from "../../src/gates/MultiplyAccumulateGates.js" 19 | import {InputGates} from "../../src/gates/InputGates.js" 20 | import {assertThatCircuitOutputsBasisKet, assertThatCircuitUpdateActsLikeMatrix} from "../CircuitOperationTestUtil.js" 21 | import {advanceStateWithCircuit} from "../../src/circuit/CircuitComputeUtil.js" 22 | 23 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 24 | import {GateColumn} from "../../src/circuit/GateColumn.js" 25 | import {Matrix} from "../../src/math/Matrix.js" 26 | 27 | let suite = new Suite("MultiplyAccumulateGates"); 28 | 29 | suite.testUsingWebGL('plus_AB', () => { 30 | assertThatCircuitUpdateActsLikeMatrix( 31 | ctx => advanceStateWithCircuit( 32 | ctx, 33 | new CircuitDefinition(5, [new GateColumn([ 34 | MultiplyAccumulateGates.MultiplyAddInputsFamily.ofSize(2), 35 | undefined, 36 | InputGates.InputAFamily.ofSize(2), 37 | undefined, 38 | InputGates.InputBFamily.ofSize(1)])]), 39 | false), 40 | Matrix.generateTransition(32, i => { 41 | let a = (i>>2)&3; 42 | let b = (i>>4)&1; 43 | let t = i & 3; 44 | return (a<<2) | (b<<4) | ((t+a*b)&3); 45 | })); 46 | }); 47 | 48 | suite.testUsingWebGL('minus_AB', () => { 49 | assertThatCircuitUpdateActsLikeMatrix( 50 | ctx => advanceStateWithCircuit( 51 | ctx, 52 | new CircuitDefinition(5, [new GateColumn([ 53 | InputGates.InputAFamily.ofSize(2), 54 | undefined, 55 | MultiplyAccumulateGates.MultiplySubtractInputsFamily.ofSize(2), 56 | undefined, 57 | InputGates.InputBFamily.ofSize(1)])]), 58 | false).output, 59 | Matrix.generateTransition(32, i => { 60 | let a = i&3; 61 | let b = (i>>4)&1; 62 | let t = (i>>2)&3; 63 | return a | (b<<4) | (((t-a*b)&3)<<2); 64 | })); 65 | }); 66 | 67 | suite.testUsingWebGL('plus_big_AB', () => { 68 | let circuit = CircuitDefinition.fromTextDiagram(new Map([ 69 | ['a', InputGates.SetA.withParam((1<<14)+1)], 70 | ['b', InputGates.SetB.withParam((1<<14)+1)], 71 | ['*', MultiplyAccumulateGates.MultiplyAddInputsFamily], 72 | ['-', undefined], 73 | ['/', null], 74 | ]), `-a-*- 75 | ---/- 76 | -b-/- 77 | ---/- 78 | ---/- 79 | ---/- 80 | ---/- 81 | ---/- 82 | ---/- 83 | ---/- 84 | ---/- 85 | ---/- 86 | ---/- 87 | ---/- 88 | ---/- 89 | ---/-`); 90 | assertThatCircuitOutputsBasisKet(circuit, 1 + (2<<14)); 91 | }); 92 | -------------------------------------------------------------------------------- /test/gates/PhaseGradientGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import { 19 | assertThatCircuitShaderActsLikeMatrix, 20 | assertThatGateActsLikePhaser, 21 | } from "../CircuitOperationTestUtil.js" 22 | import {PHASE_GRADIENT_SHADER, PhaseGradientGates} from "../../src/gates/PhaseGradientGates.js" 23 | 24 | import {Complex} from "../../src/math/Complex.js" 25 | import {Matrix} from "../../src/math/Matrix.js" 26 | import {ketArgs} from "../../src/circuit/KetShaderUtil.js" 27 | import {WglArg} from "../../src/webgl/WglArg.js" 28 | 29 | let suite = new Suite("PhaseGradientGates"); 30 | 31 | suite.testUsingWebGL('PHASE_GRADIENT_SHADER', () => { 32 | assertThatCircuitShaderActsLikeMatrix( 33 | ctx => PHASE_GRADIENT_SHADER.withArgs(...ketArgs(ctx, 3), WglArg.float('factor', Math.PI/8)), 34 | Matrix.generateDiagonal(8, i => Complex.polar(1, i*Math.PI/8))); 35 | 36 | assertThatCircuitShaderActsLikeMatrix( 37 | ctx => PHASE_GRADIENT_SHADER.withArgs(...ketArgs(ctx, 4), WglArg.float('factor', -Math.PI/16)), 38 | Matrix.generateDiagonal(16, i => Complex.polar(1, -i*Math.PI/16))); 39 | }); 40 | 41 | suite.testUsingWebGL('DynamicPhaseGradientFamily', () => { 42 | assertThatGateActsLikePhaser( 43 | PhaseGradientGates.DynamicPhaseGradientFamily.ofSize(3), 44 | k => 0.3*k, 45 | 0.3); 46 | 47 | assertThatGateActsLikePhaser( 48 | PhaseGradientGates.DynamicPhaseDegradientFamily.ofSize(2), 49 | k => -0.1*k, 50 | 0.1); 51 | }); 52 | -------------------------------------------------------------------------------- /test/gates/PivotFlipGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {assertThatCircuitOutputsBasisKet} from "../CircuitOperationTestUtil.js" 19 | 20 | import {PivotFlipGates} from "../../src/gates/PivotFlipGates.js" 21 | import {Gates} from "../../src/gates/AllGates.js" 22 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 23 | 24 | let suite = new Suite("PivotFlipGates"); 25 | 26 | suite.testUsingWebGL('pivot_flip', () => { 27 | let circ = diagram => CircuitDefinition.fromTextDiagram(new Map([ 28 | ['5', Gates.InputGates.SetA.withParam(5)], 29 | ['X', Gates.HalfTurns.X], 30 | ['F', PivotFlipGates.FlipUnderA], 31 | ['-', undefined], 32 | ['/', null], 33 | ]), diagram); 34 | 35 | assertThatCircuitOutputsBasisKet(circ(`-5-F- 36 | ---/- 37 | ---/- 38 | ---/-`), 4); 39 | 40 | assertThatCircuitOutputsBasisKet(circ(`-X-5-F- 41 | -----/- 42 | -----/- 43 | -----/-`), 3); 44 | 45 | assertThatCircuitOutputsBasisKet(circ(`---5-F- 46 | -X---/- 47 | -----/- 48 | -----/-`), 2); 49 | 50 | assertThatCircuitOutputsBasisKet(circ(`-X-5-F- 51 | -X---/- 52 | -----/- 53 | -----/-`), 1); 54 | 55 | assertThatCircuitOutputsBasisKet(circ(`---5-F- 56 | -----/- 57 | -X---/- 58 | -----/-`), 0); 59 | 60 | assertThatCircuitOutputsBasisKet(circ(`-X-5-F- 61 | -----/- 62 | -X---/- 63 | -----/-`), 5); 64 | 65 | assertThatCircuitOutputsBasisKet(circ(`-X-5-F- 66 | -----/- 67 | -X---/- 68 | -X---/-`), 13); 69 | }); 70 | -------------------------------------------------------------------------------- /test/gates/ProbabilityDisplay.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {amplitudesToProbabilities} from "../../src/gates/ProbabilityDisplay.js" 19 | 20 | import {CircuitShaders} from "../../src/circuit/CircuitShaders.js" 21 | import {Controls} from "../../src/circuit/Controls.js" 22 | import {Shaders} from "../../src/webgl/Shaders.js" 23 | 24 | let suite = new Suite("ProbabilityDisplay"); 25 | 26 | suite.testUsingWebGL("amplitudesToProbabilities", () => { 27 | let inp = Shaders.vec2Data(new Float32Array([ 28 | 2, 3, 29 | 4, 5, 30 | 6, 7, 31 | 8, 9, 32 | 1/2, 0, 33 | 0, 1/4, 34 | 0, 1/8, 35 | 1/16, 0 36 | ])).toVec2Texture(3); 37 | 38 | let con = CircuitShaders.controlMask(Controls.NONE).toBoolTexture(3); 39 | assertThat(amplitudesToProbabilities(inp, con).readVecFloatOutputs(3)).isApproximatelyEqualTo(new Float32Array([ 40 | 4+9, 41 | 16+25, 42 | 36+49, 43 | 64+81, 44 | 1/4, 45 | 1/16, 46 | 1/64, 47 | 1/256 48 | ])); 49 | 50 | inp.deallocByDepositingInPool(); 51 | con.deallocByDepositingInPool(); 52 | }); 53 | -------------------------------------------------------------------------------- /test/gates/SampleDisplay.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | 19 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 20 | import {CircuitStats} from "../../src/circuit/CircuitStats.js" 21 | import {Serializer} from "../../src/circuit/Serializer.js" 22 | 23 | let suite = new Suite("SampleDisplay"); 24 | 25 | suite.testUsingWebGL("SampleDisplay_SingleZero", () => { 26 | let stats = CircuitStats.fromCircuitAtTime( 27 | Serializer.fromJson(CircuitDefinition, {"cols":[["Sample1"]]}), 28 | 0); 29 | let out = stats.toReadableJson(); 30 | assertThat(out.displays[0].data.probabilities).isApproximatelyEqualTo([ 31 | 1, 32 | 0, 33 | ]); 34 | }); 35 | -------------------------------------------------------------------------------- /test/gates/XorGates.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite} from "../TestUtil.js" 18 | import {XorGates} from "../../src/gates/XorGates.js" 19 | import {InputGates} from "../../src/gates/InputGates.js" 20 | import {assertThatCircuitUpdateActsLikeMatrix} from "../CircuitOperationTestUtil.js" 21 | import {advanceStateWithCircuit} from "../../src/circuit/CircuitComputeUtil.js" 22 | 23 | import {CircuitDefinition} from "../../src/circuit/CircuitDefinition.js" 24 | import {GateColumn} from "../../src/circuit/GateColumn.js" 25 | import {Matrix} from "../../src/math/Matrix.js" 26 | 27 | let suite = new Suite("XorGates"); 28 | 29 | suite.testUsingWebGL('xor_a', () => { 30 | let matrix = Matrix.generateTransition(1 << 6, i => { 31 | let a = (i >> 3) & 3; 32 | let dst = i & 3; 33 | let left = i & ~3; 34 | return (a ^ dst) + left; 35 | }); 36 | 37 | assertThatCircuitUpdateActsLikeMatrix( 38 | ctx => advanceStateWithCircuit( 39 | ctx, 40 | new CircuitDefinition(6, [new GateColumn([ 41 | XorGates.XorAFamily.ofSize(2), 42 | undefined, 43 | undefined, 44 | InputGates.InputAFamily.ofSize(2), 45 | undefined, 46 | undefined])]), 47 | false), 48 | matrix); 49 | 50 | assertThatCircuitUpdateActsLikeMatrix( 51 | ctx => advanceStateWithCircuit( 52 | ctx, 53 | new CircuitDefinition(6, [new GateColumn([ 54 | XorGates.XorAFamily.ofSize(3), 55 | undefined, 56 | undefined, 57 | InputGates.InputAFamily.ofSize(2), 58 | undefined, 59 | undefined])]), 60 | false), 61 | matrix); 62 | 63 | assertThatCircuitUpdateActsLikeMatrix( 64 | ctx => advanceStateWithCircuit( 65 | ctx, 66 | new CircuitDefinition(6, [new GateColumn([ 67 | XorGates.XorAFamily.ofSize(2), 68 | undefined, 69 | undefined, 70 | InputGates.InputAFamily.ofSize(3), 71 | undefined, 72 | undefined])]), 73 | false), 74 | matrix); 75 | }); 76 | -------------------------------------------------------------------------------- /test/math/Axis.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat, assertThrows, assertTrue, assertFalse} from "../TestUtil.js" 18 | import {Axis} from "../../src/math/Axis.js" 19 | 20 | let suite = new Suite("Axis"); 21 | 22 | suite.test("isEqualTo", () => { 23 | let groups = [ 24 | [new Axis(0, 0, 0), new Axis(0, 0, 0)], 25 | [new Axis(1, 0, 0), new Axis(1, 0, 0)], 26 | [new Axis(0, 1, 0), new Axis(0, 1, 0)], 27 | [new Axis(0, 0, 1), new Axis(0, 0, 1)], 28 | [new Axis(1, 2, 3), new Axis(1, 2, 3)], 29 | [new Axis(4, 5, 6)] 30 | ]; 31 | 32 | for (let g1 of groups) { 33 | for (let g2 of groups) { 34 | for (let e1 of g1) { 35 | for (let e2 of g2) { 36 | if (g1 === g2) { 37 | assertThat(e1).isEqualTo(e2); 38 | assertTrue(e1.isEqualTo(e2)); 39 | } else { 40 | assertThat(e1).isNotEqualTo(e2); 41 | assertFalse(e1.isEqualTo(e2)); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | assertThat(new Axis(0, 0, 0)).isNotEqualTo(0); 49 | assertThat(new Axis(0, 0, 0)).isNotEqualTo(""); 50 | }); 51 | 52 | suite.test("parse", () => { 53 | assertThrows(() => Axis.parse("")); 54 | assertThrows(() => Axis.parse("0")); 55 | assertThrows(() => Axis.parse("abc")); 56 | assertThrows(() => Axis.parse("x*y")); 57 | assertThrows(() => Axis.parse("x^y")); 58 | assertThrows(() => Axis.parse("x/y")); 59 | 60 | assertThat(Axis.parse("x")).isEqualTo(new Axis(1, 0, 0)); 61 | assertThat(Axis.parse("y")).isEqualTo(new Axis(0, 1, 0)); 62 | assertThat(Axis.parse("z")).isEqualTo(new Axis(0, 0, 1)); 63 | 64 | assertThat(Axis.parse("sqrt --4 x")).isEqualTo(new Axis(2, 0, 0)); 65 | 66 | assertThat(Axis.parse("2z+3y-5x-x")).isEqualTo(new Axis(-6, 3, 2)); 67 | assertThat(Axis.parse("2z*6^2+3y-5x-x")).isEqualTo(new Axis(-6, 3, 72)); 68 | 69 | assertThat(Axis.parse("2z+")).isEqualTo(new Axis(0, 0, 2)); 70 | assertThat(Axis.parse("2z*")).isEqualTo(new Axis(0, 0, 2)); 71 | assertThat(Axis.parse("(2z)^")).isEqualTo(new Axis(0, 0, 2)); 72 | assertThat(Axis.parse("2z/")).isEqualTo(new Axis(0, 0, 2)); 73 | assertThat(Axis.parse("2z-")).isEqualTo(new Axis(0, 0, 2)); 74 | }); 75 | -------------------------------------------------------------------------------- /test/math/Point.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat, assertTrue, assertFalse} from "../TestUtil.js" 18 | import {Point} from "../../src/math/Point.js" 19 | 20 | let suite = new Suite("Point"); 21 | 22 | suite.test("isEqualTo", () => { 23 | let p = new Point(2, 3); 24 | assertTrue(p.isEqualTo(p)); 25 | assertFalse(p.isEqualTo(null)); 26 | assertFalse(p.isEqualTo("")); 27 | 28 | assertTrue(p.isEqualTo(new Point(2, 3))); 29 | assertFalse(p.isEqualTo(new Point(2, 4))); 30 | assertFalse(p.isEqualTo(new Point(1, 3))); 31 | 32 | // Interops with assertThat. 33 | assertThat(p).isEqualTo(new Point(2, 3)); 34 | assertThat(p).isNotEqualTo(new Point(2, 4)); 35 | }); 36 | 37 | suite.test("toString", () => { 38 | assertThat(new Point(2, 3).toString()).isEqualTo("(x: 2, y: 3)"); 39 | }); 40 | 41 | suite.test("offsetBy", () => { 42 | assertThat(new Point(2, 3).offsetBy(5, 7)).isEqualTo(new Point(7, 10)); 43 | }); 44 | 45 | suite.test("plus", () => { 46 | assertThat(new Point(2, 3).plus(new Point(5, 7))).isEqualTo(new Point(7, 10)); 47 | }); 48 | 49 | suite.test("minus", () => { 50 | assertThat(new Point(2, 3).minus(new Point(5, 7))).isEqualTo(new Point(-3, -4)); 51 | }); 52 | 53 | suite.test("times", () => { 54 | assertThat(new Point(2, 3).times(5)).isEqualTo(new Point(10, 15)); 55 | }); 56 | 57 | suite.test("distanceTo", () => { 58 | assertThat(new Point(2, 3).distanceTo(new Point(3, 3))).isEqualTo(1); 59 | assertThat(new Point(2, 3).distanceTo(new Point(4, 3))).isEqualTo(2); 60 | assertThat(new Point(2, 2).distanceTo(new Point(2, 3))).isEqualTo(1); 61 | assertThat(new Point(2, 2).distanceTo(new Point(2, 4))).isEqualTo(2); 62 | assertThat(new Point(0, 0).distanceTo(new Point(4, 3))).isEqualTo(5); 63 | }); 64 | -------------------------------------------------------------------------------- /test/ui/MathPainter.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {MathPainter} from "../../src/draw/MathPainter.js" 19 | 20 | let suite = new Suite("MathPainter"); 21 | 22 | suite.test("describeProbability_middle", () => { 23 | assertThat(MathPainter.describeProbability(1/3, 0)).isEqualTo("33%"); 24 | assertThat(MathPainter.describeProbability(1/3, 1)).isEqualTo("33.3%"); 25 | assertThat(MathPainter.describeProbability(1/3, 2)).isEqualTo("33.33%"); 26 | 27 | assertThat(MathPainter.describeProbability(1/2, 0)).isEqualTo("50%"); 28 | assertThat(MathPainter.describeProbability(1/2, 1)).isEqualTo("50.0%"); 29 | assertThat(MathPainter.describeProbability(1/2, 2)).isEqualTo("50.00%"); 30 | 31 | assertThat(MathPainter.describeProbability(2/3, 0)).isEqualTo("67%"); 32 | assertThat(MathPainter.describeProbability(2/3, 1)).isEqualTo("66.7%"); 33 | assertThat(MathPainter.describeProbability(2/3, 2)).isEqualTo("66.67%"); 34 | }); 35 | 36 | suite.test("describeProbability_borders", () => { 37 | assertThat(MathPainter.describeProbability(0, 0)).isEqualTo("Off"); 38 | assertThat(MathPainter.describeProbability(0, 1)).isEqualTo("Off"); 39 | assertThat(MathPainter.describeProbability(0, 2)).isEqualTo("Off"); 40 | 41 | assertThat(MathPainter.describeProbability(0.00001, 0)).isEqualTo("Off"); 42 | assertThat(MathPainter.describeProbability(0.00001, 1)).isEqualTo("Off"); 43 | assertThat(MathPainter.describeProbability(0.00001, 2)).isEqualTo("Off"); 44 | 45 | assertThat(MathPainter.describeProbability(0.004, 0)).isEqualTo("Off"); 46 | assertThat(MathPainter.describeProbability(0.0004, 0)).isEqualTo("Off"); 47 | assertThat(MathPainter.describeProbability(0.0004, 1)).isEqualTo("Off"); 48 | assertThat(MathPainter.describeProbability(0.0004, 2)).isEqualTo("0.04%"); 49 | 50 | assertThat(MathPainter.describeProbability(0.006, 0)).isEqualTo("1%"); 51 | assertThat(MathPainter.describeProbability(0.0006, 0)).isEqualTo("Off"); 52 | assertThat(MathPainter.describeProbability(0.0006, 1)).isEqualTo("0.1%"); 53 | assertThat(MathPainter.describeProbability(0.0006, 2)).isEqualTo("0.06%"); 54 | 55 | assertThat(MathPainter.describeProbability(0.996, 0)).isEqualTo("On"); 56 | assertThat(MathPainter.describeProbability(0.9996, 0)).isEqualTo("On"); 57 | assertThat(MathPainter.describeProbability(0.9996, 1)).isEqualTo("On"); 58 | assertThat(MathPainter.describeProbability(0.9996, 2)).isEqualTo("99.96%"); 59 | 60 | assertThat(MathPainter.describeProbability(0.994, 0)).isEqualTo("99%"); 61 | assertThat(MathPainter.describeProbability(0.9994, 0)).isEqualTo("On"); 62 | assertThat(MathPainter.describeProbability(0.9994, 1)).isEqualTo("99.9%"); 63 | assertThat(MathPainter.describeProbability(0.9994, 2)).isEqualTo("99.94%"); 64 | 65 | assertThat(MathPainter.describeProbability(0.99999, 0)).isEqualTo("On"); 66 | assertThat(MathPainter.describeProbability(0.99999, 1)).isEqualTo("On"); 67 | assertThat(MathPainter.describeProbability(0.99999, 2)).isEqualTo("On"); 68 | 69 | assertThat(MathPainter.describeProbability(1, 0)).isEqualTo("On"); 70 | assertThat(MathPainter.describeProbability(1, 1)).isEqualTo("On"); 71 | assertThat(MathPainter.describeProbability(1, 2)).isEqualTo("On"); 72 | }); 73 | -------------------------------------------------------------------------------- /test/ui/WidgetPainter.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {WidgetPainter} from "../../src/draw/WidgetPainter.js" 19 | 20 | import {Format} from "../../src/base/Format.js" 21 | import {Complex} from "../../src/math/Complex.js" 22 | 23 | let suite = new Suite("WidgetPainter"); 24 | 25 | suite.test("describeAxis", () => { 26 | let s = Math.sqrt(2); 27 | 28 | assertThat(WidgetPainter.describeAxis([1, 0, 0], Format.SIMPLIFIED)).isEqualTo("X"); 29 | assertThat(WidgetPainter.describeAxis([0, 1, 0], Format.SIMPLIFIED)).isEqualTo("Y"); 30 | assertThat(WidgetPainter.describeAxis([0, 0, 1], Format.SIMPLIFIED)).isEqualTo("Z"); 31 | 32 | assertThat(WidgetPainter.describeAxis([s, s, 0], Format.SIMPLIFIED)).isEqualTo("X + Y"); 33 | assertThat(WidgetPainter.describeAxis([0, s, s], Format.SIMPLIFIED)).isEqualTo("Y + Z"); 34 | assertThat(WidgetPainter.describeAxis([s, 0, s], Format.SIMPLIFIED)).isEqualTo("X + Z"); 35 | 36 | assertThat(WidgetPainter.describeAxis([-s, s, 0], Format.SIMPLIFIED)).isEqualTo("-X + Y"); 37 | assertThat(WidgetPainter.describeAxis([0, -s, s], Format.SIMPLIFIED)).isEqualTo("-Y + Z"); 38 | assertThat(WidgetPainter.describeAxis([s, 0, -s], Format.SIMPLIFIED)).isEqualTo("X - Z"); 39 | 40 | assertThat(WidgetPainter.describeAxis([1, -1, 1], Format.SIMPLIFIED)).isEqualTo("X - Y + Z"); 41 | 42 | assertThat(WidgetPainter.describeAxis([1, 0.5, 0.25], Format.SIMPLIFIED)).isEqualTo("X + ½·Y + ¼·Z"); 43 | assertThat(WidgetPainter.describeAxis([1, 0.5, 0.25], Format.CONSISTENT)).isEqualTo("X + 0.50·Y + 0.25·Z"); 44 | }); 45 | 46 | suite.test("describeKet", () => { 47 | assertThat(WidgetPainter.describeKet(1, 0, 1, Format.SIMPLIFIED)).isEqualTo('|0⟩'); 48 | assertThat(WidgetPainter.describeKet(1, 1, 1, Format.SIMPLIFIED)).isEqualTo('|1⟩'); 49 | 50 | assertThat(WidgetPainter.describeKet(2, 0, 1, Format.SIMPLIFIED)).isEqualTo('|00⟩'); 51 | assertThat(WidgetPainter.describeKet(2, 1, 1, Format.SIMPLIFIED)).isEqualTo('|01⟩'); 52 | assertThat(WidgetPainter.describeKet(2, 2, 1, Format.SIMPLIFIED)).isEqualTo('|10⟩'); 53 | assertThat(WidgetPainter.describeKet(2, 3, 1, Format.SIMPLIFIED)).isEqualTo('|11⟩'); 54 | 55 | assertThat(WidgetPainter.describeKet(2, 0, new Complex(-1, 0), Format.SIMPLIFIED)).isEqualTo('-|00⟩'); 56 | assertThat(WidgetPainter.describeKet(2, 1, Complex.I, Format.SIMPLIFIED)).isEqualTo('i|01⟩'); 57 | assertThat(WidgetPainter.describeKet(2, 2, new Complex(0, -1), Format.SIMPLIFIED)).isEqualTo('-i|10⟩'); 58 | assertThat(WidgetPainter.describeKet(2, 3, new Complex(1, 1), Format.SIMPLIFIED)).isEqualTo('(1+i)·|11⟩'); 59 | }); 60 | -------------------------------------------------------------------------------- /test/ui/forge.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat, assertThrows} from "../TestUtil.js" 18 | import {Complex} from "../../src/math/Complex.js" 19 | import {Matrix} from "../../src/math/Matrix.js" 20 | import {parseUserMatrix, parseUserRotation} from "../../src/ui/forge.js" 21 | 22 | let suite = new Suite("forge"); 23 | 24 | suite.test("parseUserMatrix", () => { 25 | assertThrows(() => parseUserMatrix("bad", false)); 26 | assertThrows(() => parseUserMatrix("{{1}}", false)); 27 | assertThrows(() => parseUserMatrix("{{1, 0}}", false)); 28 | assertThrows(() => parseUserMatrix("{{1, 0}, {2, 3}, {4, 5}}", false)); 29 | assertThrows(() => parseUserMatrix("{{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}", false)); 30 | assertThrows(() => parseUserMatrix("((1, i), (i, 1))", false)); 31 | 32 | assertThat(parseUserMatrix("0", false)).isEqualTo(Matrix.square(0, 0, 0, 0)); 33 | assertThat(parseUserMatrix("1, 2", false)).isEqualTo(Matrix.square(1, 2, 0, 0)); 34 | assertThat(parseUserMatrix("1, 2, 3+i, i^2", false)).isEqualTo(Matrix.square(1, 2, new Complex(3, 1), -1)); 35 | assertThat(parseUserMatrix("0,0,0,0,0", false)).isEqualTo(Matrix.zero(4, 4)); 36 | assertThat(parseUserMatrix("0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", false)).isEqualTo(Matrix.zero(8, 8)); 37 | 38 | let s = Math.sqrt(0.5); 39 | let si = new Complex(0, s); 40 | assertThat(parseUserMatrix("0", true)).isApproximatelyEqualTo(Matrix.square(1, 0, 0, 1)); 41 | assertThat(parseUserMatrix("1", true)).isApproximatelyEqualTo(Matrix.square(1, 0, 0, 1)); 42 | assertThat(parseUserMatrix("2", true)).isApproximatelyEqualTo(Matrix.square(1, 0, 0, 1)); 43 | assertThat(parseUserMatrix("1, 1", true)).isApproximatelyEqualTo(Matrix.square(s, s, -s, s)); 44 | assertThat(parseUserMatrix("1, i, i, 1", true)).isApproximatelyEqualTo(Matrix.square(s, si, si, s)); 45 | assertThat(parseUserMatrix("{{1, i}, {i, 1}}", true)).isApproximatelyEqualTo(Matrix.square(s, si, si, s)); 46 | assertThat(parseUserMatrix("[[1, i], [i, 1]]", true)).isApproximatelyEqualTo(Matrix.square(s, si, si, s)); 47 | 48 | assertThat(parseUserMatrix("0,0,0,0,0", true)).isApproximatelyEqualTo(Matrix.identity(4)); 49 | assertThat(parseUserMatrix("0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", true)).isApproximatelyEqualTo(Matrix.identity(8)); 50 | }); 51 | 52 | suite.test("parseUserRotation", () => { 53 | let s = Math.sqrt(0.5); 54 | let si = new Complex(0, s); 55 | assertThat(parseUserRotation("180", "90", "X")).isEqualTo(Matrix.PAULI_X); 56 | assertThat(parseUserRotation("180", "90", "Y")).isEqualTo(Matrix.PAULI_Y); 57 | assertThat(parseUserRotation("180", "90", "Z")).isEqualTo(Matrix.PAULI_Z); 58 | assertThat(parseUserRotation("180", "90", "X+Z")).isEqualTo(Matrix.HADAMARD); 59 | assertThat(parseUserRotation("90", "45", "X")).isEqualTo(Matrix.fromPauliRotation(0.25, 0, 0)); 60 | assertThat(parseUserRotation("-2*45", "2^3-8", "X")).isEqualTo(Matrix.square(s, si, si, s)); 61 | }); 62 | -------------------------------------------------------------------------------- /test/webgl/ShaderCoders_Base.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | 19 | import {BOOL_TYPE_CODER} from "../../src/webgl/ShaderCoders_Base.js" 20 | import {combinedShaderPartsWithCode, shaderWithOutputPartAndArgs} from "../../src/webgl/ShaderCoders.js" 21 | import {Shaders} from "../../src/webgl/Shaders.js" 22 | 23 | let suite = new Suite("ShaderCoders_Base"); 24 | 25 | suite.testUsingWebGLFloatTextures("boolInputs", () => { 26 | let inp = BOOL_TYPE_CODER.inputPartGetter('a'); 27 | let shader = combinedShaderPartsWithCode([inp], ` 28 | void main() { 29 | vec2 xy = gl_FragCoord.xy - vec2(0.5, 0.5); 30 | float k = xy.y * 4.0 + xy.x; 31 | gl_FragColor = vec4(read_a(k), k, 0.0, 0.0); 32 | }`); 33 | 34 | let tex = Shaders.data(new Uint8Array([255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0])).toRawByteTexture(2); 35 | assertThat(shader.withArgs(...inp.argsFor(tex)).readRawFloatOutputs(2)).isEqualTo(new Float32Array([ 36 | 1, 0, 0, 0, 37 | 0, 1, 0, 0, 38 | 0, 2, 0, 0, 39 | 1, 3, 0, 0 40 | ])); 41 | tex.deallocByDepositingInPool(); 42 | }); 43 | 44 | suite.testUsingWebGL("boolOutputs", () => { 45 | let output = BOOL_TYPE_CODER.outputPart; 46 | let shader = combinedShaderPartsWithCode([output], ` 47 | bool outputFor(float k) { 48 | return floor(mod(k + 0.5, 3.0)) == 1.0; 49 | }`); 50 | 51 | assertThat(shaderWithOutputPartAndArgs(shader, output, []).readBoolOutputs(3)).isEqualTo(new Uint8Array([ 52 | 0, 1, 0, 0, 1, 0, 0, 1 53 | ])); 54 | }); 55 | -------------------------------------------------------------------------------- /test/webgl/ShaderCoders_intoFloats.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat, assertThrows} from "../TestUtil.js" 18 | import {SHADER_CODER_FLOATS} from "../../src/webgl/ShaderCoders_intoFloats.js" 19 | import {Shaders} from "../../src/webgl/Shaders.js" 20 | 21 | let suite = new Suite("ShaderCoders"); 22 | 23 | suite.testUsingWebGLFloatTextures("packed", () => { 24 | assertThat(SHADER_CODER_FLOATS.float.dataToPixels(new Float32Array([1, 2, 3, 4]))).isEqualTo(new Float32Array([ 25 | 1, 0, 0, 0, 26 | 2, 0, 0, 0, 27 | 3, 0, 0, 0, 28 | 4, 0, 0, 0 29 | ])); 30 | 31 | assertThat(SHADER_CODER_FLOATS.vec2.dataToPixels(new Float32Array([1, 2, 3, 4]))).isEqualTo(new Float32Array([ 32 | 1, 2, 0, 0, 33 | 3, 4, 0, 0 34 | ])); 35 | 36 | assertThat(SHADER_CODER_FLOATS.vec4.dataToPixels(new Float32Array([1, 2, 3, 4]))).isEqualTo(new Float32Array([ 37 | 1, 2, 3, 4 38 | ])); 39 | }); 40 | 41 | suite.testUsingWebGLFloatTextures("input_wrongType", () => { 42 | assertThrows(() => { 43 | let tex = Shaders.data(new Uint8Array([0, 0, 0, 0])).toRawByteTexture(0); 44 | try { 45 | SHADER_CODER_FLOATS.float.inputPartGetter('a').argsFor(tex); 46 | } finally { 47 | tex.deallocByDepositingInPool(); 48 | } 49 | }); 50 | 51 | assertThrows(() => { 52 | let tex = Shaders.data(new Uint8Array([0, 0, 0, 0])).toRawByteTexture(0); 53 | try { 54 | SHADER_CODER_FLOATS.vec2.inputPartGetter('a').argsFor(tex); 55 | } finally { 56 | tex.deallocByDepositingInPool(); 57 | } 58 | }); 59 | 60 | assertThrows(() => { 61 | let tex = Shaders.data(new Uint8Array([0, 0, 0, 0])).toRawByteTexture(0); 62 | try { 63 | SHADER_CODER_FLOATS.vec4.inputPartGetter('a').argsFor(tex); 64 | } finally { 65 | tex.deallocByDepositingInPool(); 66 | } 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /test/webgl/WglShader.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {WglShader} from "../../src/webgl/WglShader.js" 19 | import {WglTexture} from "../../src/webgl/WglTexture.js" 20 | import {Seq} from "../../src/base/Seq.js" 21 | import {initializedWglContext} from "../../src/webgl/WglContext.js" 22 | 23 | let suite = new Suite("WglShader"); 24 | 25 | suite.testUsingWebGL("renderTo_large", () => { 26 | let tex = new WglTexture(256, 256, WebGLRenderingContext.UNSIGNED_BYTE); 27 | new WglShader("void main(){gl_FragColor=vec4(3.0,3.0,3.0,3.0)/255.0;}").withArgs().renderTo(tex); 28 | let expected = new Uint8Array(Seq.repeat(3, 4 * tex.width * tex.height).toArray()); 29 | assertThat(tex.readPixels()).isEqualTo(expected); 30 | }); 31 | 32 | suite.testUsingWebGLFloatTextures("renderTo_empty", () => { 33 | let tex = new WglTexture(0, 0); 34 | new WglShader("void main(){gl_FragColor=vec4(0.0,0.0,0.0,0.0);}").withArgs().renderTo(tex); 35 | assertThat(tex.readPixels()).isEqualTo(new Float32Array([])); 36 | }); 37 | 38 | suite.testUsingWebGL("readPixels_bytes_all", () => { 39 | let shader = new WglShader(` 40 | void main() { 41 | vec2 xy = gl_FragCoord.xy - vec2(0.5, 0.5); 42 | float s = (xy.y*8.0 + xy.x)*4.0; 43 | gl_FragColor = vec4( 44 | (s+0.0)/255.0, 45 | (s+1.0)/255.0, 46 | (s+2.0)/255.0, 47 | (s+3.0)/255.0); 48 | }`).withArgs(); 49 | 50 | let tex = new WglTexture(8, 8, WebGLRenderingContext.UNSIGNED_BYTE); 51 | shader.renderTo(tex); 52 | assertThat(tex.readPixels()).isEqualTo(new Uint8Array( 53 | Seq.range(256).toArray() 54 | )); 55 | tex.ensureDeinitialized(); 56 | }); 57 | 58 | suite.testUsingWebGLFloatTextures("changeSourceAfterInvalidate", () => { 59 | let tex = new WglTexture(1, 1); 60 | let flag = true; 61 | let shader = new WglShader(() => flag ? 62 | "void main(){gl_FragColor=vec4(-5.0,-6.0,7.0,8.0);}" : 63 | "void main(){gl_FragColor=vec4(1.0,2.0,3.0,4.0);}"); 64 | 65 | shader.withArgs().renderTo(tex); 66 | assertThat(tex.readPixels()).isEqualTo(new Float32Array([-5, -6, 7, 8])); 67 | 68 | flag = false; 69 | initializedWglContext().invalidateExistingResources(); 70 | 71 | shader.withArgs().renderTo(tex); 72 | assertThat(tex.readPixels()).isEqualTo(new Float32Array([1, 2, 3, 4])); 73 | }); 74 | -------------------------------------------------------------------------------- /test/webgl/WglTexture.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import {WglArg} from "../../src/webgl/WglArg.js" 19 | import {WglShader} from "../../src/webgl/WglShader.js" 20 | import {WglTexture} from "../../src/webgl/WglTexture.js" 21 | 22 | let suite = new Suite("WglTexture"); 23 | 24 | suite.test("properties", () => { 25 | let t = new WglTexture(8, 16, WebGLRenderingContext.UNSIGNED_BYTE); 26 | assertThat(t.width).isEqualTo(8); 27 | assertThat(t.height).isEqualTo(16); 28 | assertThat(t.pixelType).isEqualTo(WebGLRenderingContext.UNSIGNED_BYTE); 29 | assertThat(t.sizePower()).isEqualTo(7); 30 | assertThat(t.toString()).isNotEqualTo(undefined); 31 | }); 32 | 33 | suite.testUsingWebGL("readPixels_bytes", () => { 34 | let w = 2; 35 | let h = 2; 36 | let shader = new WglShader(` 37 | uniform float v; 38 | void main() { 39 | vec2 xy = gl_FragCoord.xy - vec2(0.5, 0.5); 40 | gl_FragColor = vec4(xy / 255.0, v, 128.0/255.0); 41 | }`); 42 | 43 | let texture = new WglTexture(w, h, WebGLRenderingContext.UNSIGNED_BYTE); 44 | 45 | shader.withArgs(WglArg.float("v", 10/255)).renderTo(texture); 46 | assertThat(texture.readPixels()).isEqualTo(new Uint8Array([ 47 | 0, 0, 10, 128, 48 | 1, 0, 10, 128, 49 | 0, 1, 10, 128, 50 | 1, 1, 10, 128 51 | ])); 52 | }); 53 | 54 | suite.testUsingWebGLFloatTextures("readPixels_floats", () => { 55 | let w = 2; 56 | let h = 2; 57 | let shader = new WglShader(` 58 | uniform float v; 59 | void main() { 60 | gl_FragColor = vec4(gl_FragCoord.xy, v, 254.5); 61 | }`); 62 | 63 | let texture = new WglTexture(w, h); 64 | 65 | shader.withArgs(WglArg.float("v", 192.25)).renderTo(texture); 66 | assertThat(texture.readPixels()).isEqualTo(new Float32Array([ 67 | 0.5, 0.5, 192.25, 254.5, 68 | 1.5, 0.5, 192.25, 254.5, 69 | 0.5, 1.5, 192.25, 254.5, 70 | 1.5, 1.5, 192.25, 254.5 71 | ])); 72 | }); 73 | 74 | suite.testUsingWebGL("readPixels_empty", () => { 75 | assertThat(new WglTexture(0, 0).readPixels()).isEqualTo(new Float32Array([])); 76 | }); 77 | -------------------------------------------------------------------------------- /test/webgl/WglTexturePool.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Suite, assertThat} from "../TestUtil.js" 18 | import { 19 | currentShaderCoder, 20 | Outputs, 21 | makePseudoShaderWithInputsAndOutputAndCode 22 | } from "../../src/webgl/ShaderCoders.js" 23 | import {WglTexturePool} from "../../src/webgl/WglTexturePool.js" 24 | 25 | let suite = new Suite("WglTexturePool"); 26 | 27 | suite.testUsingWebGL("takeBoolTex", () => { 28 | let t = WglTexturePool.takeBoolTex(2); 29 | makePseudoShaderWithInputsAndOutputAndCode( 30 | [], 31 | Outputs.bool(), 32 | `bool outputFor(float k) { 33 | return k == 2.0; 34 | }`)().renderTo(t); 35 | assertThat(t.readPixels()).isEqualTo(new Uint8Array([ 36 | 0, 0, 0, 0, 37 | 0, 0, 0, 0, 38 | 255, 0, 0, 0, 39 | 0, 0, 0, 0 40 | ])); 41 | t.deallocByDepositingInPool(); 42 | }); 43 | 44 | suite.testUsingWebGLFloatTextures("takeVec2Tex", () => { 45 | let t = WglTexturePool.takeVec2Tex(2); 46 | makePseudoShaderWithInputsAndOutputAndCode( 47 | [], 48 | Outputs.vec2(), 49 | `vec2 outputFor(float k) { 50 | return vec2(k / 4.0, k * k); 51 | }`)().renderTo(t); 52 | assertThat(currentShaderCoder().vec2.pixelsToData(t.readPixels())).isEqualTo(new Float32Array([ 53 | 0, 0, 54 | 0.25, 1, 55 | 0.5, 4, 56 | 0.75, 9 57 | ])); 58 | t.deallocByDepositingInPool(); 59 | }); 60 | 61 | suite.testUsingWebGLFloatTextures("takeVec4Tex", () => { 62 | let t = WglTexturePool.takeVec4Tex(2); 63 | makePseudoShaderWithInputsAndOutputAndCode( 64 | [], 65 | Outputs.vec4(), 66 | `vec4 outputFor(float k) { 67 | return vec4(k, k / 4.0, k * k, 5.0); 68 | }`)().renderTo(t); 69 | assertThat(currentShaderCoder().vec4.pixelsToData(t.readPixels())).isEqualTo(new Float32Array([ 70 | 0, 0, 0, 5, 71 | 1, 0.25, 1, 5, 72 | 2, 0.5, 4, 5, 73 | 3, 0.75, 9, 5 74 | ])); 75 | t.deallocByDepositingInPool(); 76 | }); 77 | -------------------------------------------------------------------------------- /test_perf/KarmaTestRunner.perf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {getKnownPerfTests} from "./TestPerfUtil.js"; 18 | 19 | let execIntoPromise = method => { 20 | try { 21 | return Promise.resolve(method()); 22 | } catch (ex) { 23 | return Promise.reject(ex); 24 | } 25 | }; 26 | 27 | let promiseRunPerfTest = ({name, method}) => { 28 | let result = { 29 | description: name, 30 | suite: ['(Perf Tests)'], 31 | success: false, 32 | log: [], 33 | time: undefined 34 | }; 35 | 36 | let t0 = performance.now(); 37 | return execIntoPromise(method).then( 38 | ({pass, info}) => { 39 | result.success = pass; 40 | result.log.push(info); 41 | }, 42 | ex => { 43 | result.log.push(String(ex)); 44 | if (ex.details !== undefined) { 45 | result.log.push(ex.details); 46 | } 47 | if (ex.stack !== undefined) { 48 | result.log.push(ex.stack); 49 | } 50 | }).then(() => { 51 | result.time = performance.now() - t0; 52 | __karma__.result(result); 53 | }); 54 | }; 55 | 56 | __karma__.start = () => { 57 | let known = getKnownPerfTests(); 58 | __karma__.info({ total: known.length }); 59 | 60 | let chain = Promise.resolve(); 61 | for (let test of known) { 62 | chain = chain.then(() => 63 | new Promise(resolver => 64 | setTimeout(() => 65 | resolver(promiseRunPerfTest(test)), 66 | 25))); 67 | } 68 | 69 | chain.then(() => __karma__.complete()); 70 | }; 71 | -------------------------------------------------------------------------------- /test_perf/TestPerfUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {} from "../src/browser/Polyfills.js" 18 | 19 | function nanos(nanoseconds) { 20 | return { 21 | duration_nanos: nanoseconds, 22 | description: nanoseconds + " ns" 23 | }; 24 | } 25 | 26 | function micros(microseconds) { 27 | return { 28 | duration_nanos: microseconds * 1.0e3, 29 | description: microseconds + " us" 30 | }; 31 | } 32 | 33 | function millis(milliseconds) { 34 | return { 35 | duration_nanos: milliseconds * 1.0e6, 36 | description: milliseconds + " ms" 37 | }; 38 | } 39 | 40 | let _knownPerfTests = []; 41 | function getKnownPerfTests() { 42 | return _knownPerfTests; 43 | } 44 | 45 | /** 46 | * @param {!string} name 47 | * @param {!{duration_nanos: !int, description: !string}} targetDuration 48 | * @param {!function(*):*} method 49 | * @param {undefined|*=undefined} arg 50 | * @param {!function(*):void} cleanup 51 | */ 52 | function perfGoal(name, targetDuration, method, arg=undefined, cleanup=undefined) { 53 | //noinspection JSUnusedGlobalSymbols 54 | _knownPerfTests.push({name, method: () => { 55 | let dt = _measureDuration(method, arg, targetDuration.duration_nanos); 56 | if (cleanup !== undefined) { 57 | cleanup(arg); 58 | } 59 | let p = dt.duration_nanos / targetDuration.duration_nanos; 60 | let pass = dt.duration_nanos <= targetDuration.duration_nanos; 61 | let info = `${_proportionDesc(p)} of goal [${_pad(targetDuration.description, 6)}] for ${name}`; 62 | if (pass) { 63 | console.log(info); 64 | } else { 65 | console.warn(info); 66 | } 67 | return {pass, info} 68 | }}); 69 | } 70 | 71 | function _pad(obj, length) { 72 | let v = `${obj}`; 73 | return ' '.repeat(Math.max(0, length - v.length)) + v; 74 | } 75 | 76 | function _proportionDesc(proportion) { 77 | return `[${_proportionBar(proportion)}] finished in ${_pad(Math.round(proportion*100), 2)}%`; 78 | } 79 | 80 | function _proportionBar(proportion, length=20) { 81 | if (proportion > 1) { 82 | return '!'.repeat(length); 83 | } 84 | let n = Math.round(proportion * length); 85 | return '#'.repeat(n) + ' '.repeat(length - n); 86 | } 87 | 88 | function _measureDuration(method, arg, expected_nanos_hint) { 89 | let ms = 1.0e6; 90 | let repeats = expected_nanos_hint < 5 * ms ? 100 : 91 | expected_nanos_hint < 30 * ms ? 50 : 92 | 10; 93 | // Dry run to get any one-time initialization done. 94 | method(arg); 95 | 96 | let t0 = window.performance.now(); 97 | for (let i = 0; i < repeats; i++) { 98 | method(arg); 99 | } 100 | let t1 = window.performance.now(); 101 | return {duration_nanos: (t1 - t0) / repeats * ms}; 102 | } 103 | 104 | export {getKnownPerfTests, perfGoal, nanos, micros, millis} 105 | -------------------------------------------------------------------------------- /test_perf/test_page.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
 9 |         
10 | 54 | 55 | 56 | --------------------------------------------------------------------------------