├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── Build.yml │ ├── codeql-analysis.yml │ ├── dotnet-core.yml │ └── publish.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── OpenQasm.sln ├── README.md ├── build └── step-build-samples.yml ├── src ├── OpenQasmExporter │ ├── Exporter.cs │ ├── ExporterMagic.cs │ ├── Intrinsics.cs │ ├── OpenQasmExporter.csproj │ └── README.md └── OpenQasmReader │ ├── OpenQasmReader.csproj │ ├── Parser.cs │ └── README.md └── tests ├── OpenQasmExporter.Sample ├── OpenQasmExporter.Sample.csproj ├── Program.cs └── SampleExporterMagic.ipynb ├── OpenQasmExporter.Tests ├── OpenQasmExporter.Tests.csproj └── Test.qs └── OpenQasmReader.Tests ├── End2EndTest.cs ├── FirstLetterToUpperCaseTest.cs ├── IndexedCallTest.cs ├── OpenQasmReader.Tests.csproj ├── ParseApplicationTest.cs ├── ParseBarrierTest.cs ├── ParseCalculationTest.cs ├── ParseConditionTest.cs ├── ParseIncludeTest.cs ├── ParseOpenQasmHeaderTest.cs ├── Test ├── 5qubit1.qasm ├── CNot.qasm ├── Gates.qasm ├── Hadamard.qasm ├── bv3.qasm ├── hid3.qasm ├── marg5.qasm └── toff6.qasm ├── TokenizerTest.cs └── Validate ├── Bv3.qs ├── CNot.qs ├── FiveQubit1.qs ├── Gates.qs ├── Hadamard.qs ├── Hid3.qs ├── Marg5.qs └── Toff6.qs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | *.sh text eol=lf 6 | 7 | ############################################################################### 8 | # diff behavior for some non-binary formats 9 | ############################################################################### 10 | *.md diff=text 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/Build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Setup .NET Core 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: 3.1.101 19 | - name: Install dependencies 20 | run: dotnet restore 21 | - name: Build 22 | run: dotnet build --configuration Release --no-restore 23 | - name: Test 24 | run: dotnet test --no-restore --verbosity normal 25 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '33 5 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 3.1.101 20 | - name: Install dependencies 21 | run: dotnet restore 22 | - name: Build 23 | run: dotnet build --configuration Release --no-restore 24 | - name: Test 25 | run: dotnet test --no-restore --verbosity normal 26 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Publish to GitHub Packages 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [ master ] 10 | 11 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 12 | jobs: 13 | # This workflow contains a single job called "build" 14 | build: 15 | # The type of runner that the job will run on 16 | runs-on: windows-latest 17 | 18 | # Steps represent a sequence of tasks that will be executed as part of the job 19 | steps: 20 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 21 | - uses: actions/checkout@v2 22 | # https://stackoverflow.com/questions/57889719/how-to-push-nuget-package-in-github-actions 23 | - name: "Setup .NET Core @ Latest" 24 | uses: actions/setup-dotnet@v1 25 | with: 26 | dotnet-version: '3.1.x' 27 | source-url: https://nuget.pkg.github.com/qsharp-community/index.json 28 | env: 29 | NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 30 | - name: Install dependencies 31 | run: dotnet restore 32 | - name: Build 33 | run: dotnet build --configuration Release --no-restore 34 | # Runs a set of commands using the runners shell 35 | - name: .NET pack 36 | run: dotnet pack -c Release -o ../drop /p:Version="0.1.$Env:GITHUB_RUN_NUMBER" 37 | shell: pwsh 38 | working-directory: src/OpenQasmExporter 39 | 40 | - name: Push to GitHub Packages 41 | run: dotnet nuget push (Join-Path "src" "drop" "*.nupkg") 42 | shell: pwsh 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python temporary files 2 | .ipynb_checkpoints 3 | 4 | # Git ignore file for the Solid project 5 | 6 | # Build artifacts 7 | *.g.cs 8 | bin/ 9 | obj/ 10 | Documentation/Help/ 11 | packages/ 12 | *.obj 13 | *.dll 14 | *.pdb 15 | *.exe 16 | *.chm 17 | 18 | # test outputs 19 | TestResults/ 20 | *.qxe 21 | 22 | # Random VS files 23 | *.suo 24 | *.vssscc 25 | *.vspscc 26 | UpgradeLog.htm 27 | 28 | # Random non-solution files 29 | ~$Solid.docx 30 | .vscode 31 | 32 | ## Ignore Visual Studio temporary files, build results, and 33 | ## files generated by popular Visual Studio add-ons. 34 | ## 35 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 36 | 37 | # User-specific files 38 | *.suo 39 | *.user 40 | *.userosscache 41 | *.sln.docstates 42 | 43 | # User-specific files (MonoDevelop/Xamarin Studio) 44 | *.userprefs 45 | 46 | # Build results 47 | [Dd]ebug/ 48 | [Dd]ebugPublic/ 49 | [Rr]elease/ 50 | [Rr]eleases/ 51 | x64/ 52 | x86/ 53 | bld/ 54 | [Bb]in/ 55 | [Oo]bj/ 56 | [Ll]og/ 57 | 58 | # Visual Studio 2015 cache/options directory 59 | .vs/ 60 | # Uncomment if you have tasks that create the project's static files in wwwroot 61 | #wwwroot/ 62 | 63 | # MSTest test Results 64 | [Tt]est[Rr]esult*/ 65 | [Bb]uild[Ll]og.* 66 | 67 | # NUNIT 68 | *.VisualState.xml 69 | TestResult.xml 70 | 71 | # Build Results of an ATL Project 72 | [Dd]ebugPS/ 73 | [Rr]eleasePS/ 74 | dlldata.c 75 | 76 | # Benchmark Results 77 | BenchmarkDotNet.Artifacts/ 78 | 79 | # .NET Core 80 | project.lock.json 81 | project.fragment.lock.json 82 | artifacts/ 83 | **/Properties/launchSettings.json 84 | 85 | *_i.c 86 | *_p.c 87 | *_i.h 88 | *.ilk 89 | *.meta 90 | *.obj 91 | *.pch 92 | *.pdb 93 | *.pgc 94 | *.pgd 95 | *.rsp 96 | *.sbr 97 | *.tlb 98 | *.tli 99 | *.tlh 100 | *.tmp 101 | *.tmp_proj 102 | *.log 103 | *.vspscc 104 | *.vssscc 105 | .builds 106 | *.pidb 107 | *.svclog 108 | *.scc 109 | 110 | # Chutzpah Test files 111 | _Chutzpah* 112 | 113 | # Visual C++ cache files 114 | ipch/ 115 | *.aps 116 | *.ncb 117 | *.opendb 118 | *.opensdf 119 | *.sdf 120 | *.cachefile 121 | *.VC.db 122 | *.VC.VC.opendb 123 | 124 | # Visual Studio profiler 125 | *.psess 126 | *.vsp 127 | *.vspx 128 | *.sap 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # JustCode is a .NET coding add-in 142 | .JustCode 143 | 144 | # TeamCity is a build add-in 145 | _TeamCity* 146 | 147 | # DotCover is a Code Coverage Tool 148 | *.dotCover 149 | 150 | # AxoCover is a Code Coverage Tool 151 | .axoCover/* 152 | !.axoCover/settings.json 153 | 154 | # Visual Studio code coverage results 155 | *.coverage 156 | *.coveragexml 157 | 158 | # NCrunch 159 | _NCrunch_* 160 | .*crunch*.local.xml 161 | nCrunchTemp_* 162 | 163 | # MightyMoose 164 | *.mm.* 165 | AutoTest.Net/ 166 | 167 | # Web workbench (sass) 168 | .sass-cache/ 169 | 170 | # Installshield output folder 171 | [Ee]xpress/ 172 | 173 | # DocProject is a documentation generator add-in 174 | DocProject/buildhelp/ 175 | DocProject/Help/*.HxT 176 | DocProject/Help/*.HxC 177 | DocProject/Help/*.hhc 178 | DocProject/Help/*.hhk 179 | DocProject/Help/*.hhp 180 | DocProject/Help/Html2 181 | DocProject/Help/html 182 | 183 | # Click-Once directory 184 | publish/ 185 | 186 | # Publish Web Output 187 | *.[Pp]ublish.xml 188 | *.azurePubxml 189 | # Note: Comment the next line if you want to checkin your web deploy settings, 190 | # but database connection strings (with potential passwords) will be unencrypted 191 | *.pubxml 192 | *.publishproj 193 | 194 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 195 | # checkin your Azure Web App publish settings, but sensitive information contained 196 | # in these scripts will be unencrypted 197 | PublishScripts/ 198 | 199 | # NuGet Packages 200 | *.nupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/packages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/packages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/packages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Since there are multiple workflows, uncomment next line to ignore bower_components 244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 245 | #bower_components/ 246 | 247 | # RIA/Silverlight projects 248 | Generated_Code/ 249 | 250 | # Backup & report files from converting an old project file 251 | # to a newer Visual Studio version. Backup files are not needed, 252 | # because we have git ;-) 253 | _UpgradeReport_Files/ 254 | Backup*/ 255 | UpgradeLog*.XML 256 | UpgradeLog*.htm 257 | 258 | # SQL Server files 259 | *.mdf 260 | *.ldf 261 | *.ndf 262 | 263 | # Business Intelligence projects 264 | *.rdl.data 265 | *.bim.layout 266 | *.bim_*.settings 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Typescript v1 declaration files 279 | typings/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # JetBrains Rider 306 | .idea/ 307 | *.sln.iml 308 | 309 | # CodeRush 310 | .cr/ 311 | 312 | # Python Tools for Visual Studio (PTVS) 313 | __pycache__/ 314 | *.pyc 315 | 316 | # Cake - Uncomment if you are using it 317 | # tools/** 318 | # !tools/packages.config 319 | 320 | # Tabs Studio 321 | *.tss 322 | 323 | # Telerik's JustMock configuration file 324 | *.jmconfig 325 | 326 | # BizTalk build output 327 | *.btp.cs 328 | *.btm.cs 329 | *.odx.cs 330 | *.xsd.cs 331 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at sckaiser@sckaiser.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /OpenQasm.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30225.117 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenQasmReader", "src\OpenQasmReader\OpenQasmReader.csproj", "{C3535767-3202-4313-B836-266A4FD7B9BF}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenQasmExporter", "src\OpenQasmExporter\OpenQasmExporter.csproj", "{FE19CF02-FD8B-461A-A21C-6A6825B922BE}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenQasmExporter.Tests", "tests\OpenQasmExporter.Tests\OpenQasmExporter.Tests.csproj", "{EDF41E61-F3C4-43AC-9413-9AD9150FCD65}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenQasmReader.Tests", "tests\OpenQasmReader.Tests\OpenQasmReader.Tests.csproj", "{0F3A4F93-4118-4F21-A8F5-DD5510EE566A}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenQasmExporter.Sample", "tests\OpenQasmExporter.Sample\OpenQasmExporter.Sample.csproj", "{B9F971F0-3614-4E27-95F4-11F781FD8B9A}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {C3535767-3202-4313-B836-266A4FD7B9BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {C3535767-3202-4313-B836-266A4FD7B9BF}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {C3535767-3202-4313-B836-266A4FD7B9BF}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {C3535767-3202-4313-B836-266A4FD7B9BF}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {FE19CF02-FD8B-461A-A21C-6A6825B922BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {FE19CF02-FD8B-461A-A21C-6A6825B922BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {FE19CF02-FD8B-461A-A21C-6A6825B922BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {FE19CF02-FD8B-461A-A21C-6A6825B922BE}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {EDF41E61-F3C4-43AC-9413-9AD9150FCD65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {EDF41E61-F3C4-43AC-9413-9AD9150FCD65}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {EDF41E61-F3C4-43AC-9413-9AD9150FCD65}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {EDF41E61-F3C4-43AC-9413-9AD9150FCD65}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {0F3A4F93-4118-4F21-A8F5-DD5510EE566A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {0F3A4F93-4118-4F21-A8F5-DD5510EE566A}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {0F3A4F93-4118-4F21-A8F5-DD5510EE566A}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {0F3A4F93-4118-4F21-A8F5-DD5510EE566A}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {B9F971F0-3614-4E27-95F4-11F781FD8B9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {B9F971F0-3614-4E27-95F4-11F781FD8B9A}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {B9F971F0-3614-4E27-95F4-11F781FD8B9A}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {B9F971F0-3614-4E27-95F4-11F781FD8B9A}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {AB5CA9E9-FFBA-435F-907C-08F34DF1D3DC} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Q# Community Integration # 2 | 3 | These samples demonstrate integration between the Q# language infrastructure/drivers and other languages. 4 | Currently present are the following integrations: 5 | 6 | ![Build](https://github.com/qsharp-community/qsharp-integrations/workflows/Build/badge.svg) 7 | 8 | ## 0. Qasm (Quantum Assembler Language) ## 9 | 10 | - **[OpenQasmReader](./src/OpenQasmReader)**: 11 | This sample shows that one can convert OpenQasm 2.0 specifications to Q# methods. This allows one to import algorithms written in OpenQasm 2.0 to be used on the Microsoft Q# Simulator. Apart of the barrier gate (which has no meaning in Q#) all gates are converted to Q# constructions. 12 | - **[OpenQasmExporter](./src/OpenQasmExporter)**: 13 | This sample shows that one can convert Q# methods to OpenQasm 2.0 specifications. This allows one to export algorithms written in Q# to OpenQasm 2.0. 14 | -------------------------------------------------------------------------------- /build/step-build-samples.yml: -------------------------------------------------------------------------------- 1 | ## 2 | # Builds, tests & package all samples. 3 | ## 4 | 5 | steps: 6 | ## 7 | # Build 8 | ## 9 | - task: DotNetCoreCLI@2 10 | displayName: 'Build Samples' 11 | inputs: 12 | projects: '$(SamplesRootFolder)/**/*.sln' 13 | arguments: '-c $(BuildConfiguration) -v n' 14 | 15 | 16 | - task: DotNetCoreCLI@2 17 | displayName: 'Test Samples' 18 | inputs: 19 | command: test 20 | projects: | 21 | $(SamplesRootFolder)/tests/OpenQasmReader.Tests 22 | arguments: '-c $(BuildConfiguration) -v n' 23 | -------------------------------------------------------------------------------- /src/OpenQasmExporter/Exporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using Microsoft.Quantum.Intrinsic; 7 | using Microsoft.Quantum.Simulation.Common; 8 | using Microsoft.Quantum.Simulation.Core; 9 | using QSharpCommunity.Simulators.OpenQasmExporter.Circuits; 10 | 11 | namespace QSharpCommunity.Simulators.OpenQasmExporter 12 | { 13 | public class Exporter : SimulatorBase, IDisposable 14 | { 15 | class ConsoleToFileWriter : TextWriter, IDisposable 16 | { 17 | public override Encoding Encoding => m_PreviousConsoleOutput.Encoding; 18 | 19 | TextWriter m_PreviousConsoleOutput; 20 | FileStream m_OutputFile; 21 | StreamWriter m_StreamWriter; 22 | 23 | public ConsoleToFileWriter(TextWriter consoleTextWriter, string outputFileName) 24 | { 25 | m_PreviousConsoleOutput = consoleTextWriter; 26 | 27 | try 28 | { 29 | if (!Path.IsPathRooted(outputFileName)) 30 | { 31 | // TODO: Figure out how to get output to the same directory that `dotnet run` occurs (e.g. the main project directory) 32 | // Console.WriteLine($"{Directory.GetCurrentDirectory()}"); 33 | // outputFileName = $"{Directory.GetCurrentDirectory()}{outputFileName}"; 34 | } 35 | 36 | m_OutputFile = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.Write); 37 | m_StreamWriter = new StreamWriter(m_OutputFile); 38 | 39 | Console.SetOut(this); 40 | } 41 | catch (Exception e) 42 | { 43 | Console.WriteLine($"Cannot open {outputFileName} for writing"); 44 | Console.WriteLine(e.Message); 45 | } 46 | } 47 | 48 | public override void Write(string message) 49 | { 50 | m_PreviousConsoleOutput.Write(message); 51 | m_StreamWriter.Write(message); 52 | } 53 | 54 | public override void WriteLine(string message) 55 | { 56 | m_PreviousConsoleOutput.WriteLine(message); 57 | m_StreamWriter.WriteLine(message); 58 | } 59 | 60 | public new void Dispose() 61 | { 62 | Console.SetOut(m_PreviousConsoleOutput); 63 | m_StreamWriter?.Close(); 64 | m_OutputFile?.Close(); 65 | } 66 | } 67 | public override string Name => nameof(Exporter); 68 | 69 | const string k_DefaultOutputFileName = "output.qasm"; 70 | const int k_MaxQubits = 32; 71 | 72 | ConsoleToFileWriter m_ConsoleToFileWriter; 73 | 74 | public Exporter(string outputFileName, TextWriter outputTextWriter) 75 | : base(new QubitManager(k_MaxQubits, true)) 76 | { 77 | m_ConsoleToFileWriter = new ConsoleToFileWriter(outputTextWriter, outputFileName); 78 | 79 | RegisterPrimitiveOperationsGivenAsCircuits(); 80 | 81 | Console.WriteLine("OPENQASM 2.0;"); 82 | Console.WriteLine("include \"qelib1.inc\";"); 83 | Console.WriteLine($"qreg q[{k_MaxQubits}];"); 84 | Console.WriteLine($"creg c[{k_MaxQubits}];"); 85 | } 86 | 87 | public Exporter(TextWriter outputTextWriter) 88 | : this(k_DefaultOutputFileName, outputTextWriter) 89 | { 90 | } 91 | 92 | public Exporter(string outputFileName) 93 | : this(outputFileName, Console.Out) 94 | { 95 | } 96 | 97 | public Exporter() 98 | : this(Console.Out) 99 | { 100 | } 101 | 102 | public void Dispose() 103 | { 104 | m_ConsoleToFileWriter.Dispose(); 105 | } 106 | 107 | void RegisterPrimitiveOperationsGivenAsCircuits() 108 | { 109 | var primitiveOperationTypes = 110 | from op in typeof(X).Assembly.GetExportedTypes() 111 | where op.IsSubclassOf(typeof(AbstractCallable)) 112 | select op; 113 | 114 | var primitiveOperationAsCircuits = 115 | from op in typeof(SingleQubitOp<>).Assembly.GetExportedTypes() 116 | where op.IsSubclassOf(typeof(AbstractCallable)) 117 | && op.Namespace == typeof(SingleQubitOp<>).Namespace 118 | select op; 119 | 120 | foreach (var operationType in primitiveOperationTypes) 121 | { 122 | var matchingCircuitTypes = 123 | from op in primitiveOperationAsCircuits 124 | where op.Name == operationType.Name 125 | select op; 126 | 127 | var numberOfMatchesFound = matchingCircuitTypes.Count(); 128 | if (numberOfMatchesFound == 0) 129 | { 130 | // Use a default 131 | if (typeof(Unitary).IsAssignableFrom(operationType)) 132 | { 133 | var genericType = typeof(SingleQubitOp<>).MakeGenericType(operationType); 134 | Register(operationType, genericType, typeof(ICallable)); 135 | continue; 136 | } 137 | } 138 | 139 | Debug.Assert( 140 | numberOfMatchesFound <= 1, 141 | "There should be at most one matching operation."); 142 | 143 | if (numberOfMatchesFound == 1) 144 | Register(operationType, matchingCircuitTypes.First(), typeof(ICallable)); 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/OpenQasmExporter/ExporterMagic.cs: -------------------------------------------------------------------------------- 1 | // Adapted from CHP magic command in the CHP-Sim project here: 2 | // https://github.com/qsharp-community/chp-sim/blob/master/src/jupyter/ChpMagic.cs 3 | 4 | namespace QSharpCommunity.Simulators.OpenQasmExporter 5 | { 6 | using System; 7 | using System.IO; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using Microsoft.Jupyter.Core; 11 | using Microsoft.Quantum.IQSharp; 12 | using Microsoft.Quantum.IQSharp.Jupyter; 13 | 14 | /// 15 | /// Runs a given function or operation on the OpenQasmExporter target machine. 16 | /// 17 | public class ExporterMagic : AbstractMagic 18 | { 19 | class ChannelTextWriter : TextWriter 20 | { 21 | public override Encoding Encoding => Console.OutputEncoding; 22 | 23 | IChannel m_Channel; 24 | 25 | public ChannelTextWriter(IChannel channel) 26 | { 27 | m_Channel = channel; 28 | } 29 | 30 | public override void Write(string message) => m_Channel.Stdout(message); 31 | 32 | public override void WriteLine(string message) => m_Channel.Stdout(message); 33 | } 34 | 35 | const string ParameterNameOperationName = "__operationName__"; 36 | readonly IConfigurationSource configurationSource; 37 | 38 | /// 39 | /// Initializes a new instance of the class. 40 | /// Default constructor. 41 | /// 42 | /// Symbol resolver. 43 | /// Source for confirgarion settings. 44 | public ExporterMagic(ISymbolResolver resolver, IConfigurationSource configurationSource) 45 | : base( 46 | "qasmexport", 47 | new Documentation 48 | { 49 | Summary = "Runs a given function or operation using the OpenQasmExporter.", 50 | Description = @" 51 | This magic command allows executing a given function or operation on the OpenQasmExporter, 52 | which performs a simulation of the given function or operation and translates it to the OpenQasm language 53 | 54 | #### Required parameters 55 | 56 | - Q# operation or function name. This must be the first parameter, and must be a valid Q# operation 57 | or function name that has been defined either in the notebook or in a Q# file in the same folder. 58 | - Arguments for the Q# operation or function must also be specified as `key=value` pairs. 59 | ", 60 | Examples = new[] 61 | { 62 | @" 63 | Use the OpenQasmExporter to simulate a Q# operation 64 | defined as `operation MyOperation() : Result`: 65 | ``` 66 | In []: %qasmexport MyOperation 67 | Out[]: 68 | ``` 69 | ", 70 | @" 71 | Use the OpenQasmExporter to simulate a Q# operation 72 | defined as `operation MyOperation(a : Int, b : Int) : Result`: 73 | ``` 74 | In []: %qasmexporter MyOperation a=5 b=10 75 | Out[]: 76 | ``` 77 | ", 78 | }, 79 | }) 80 | { 81 | this.SymbolResolver = resolver; 82 | this.configurationSource = configurationSource; 83 | } 84 | 85 | /// 86 | /// Gets the ISymbolResolver used to find the function/operation to simulate. 87 | /// 88 | public ISymbolResolver SymbolResolver { get; } 89 | 90 | /// 91 | public override ExecutionResult Run(string input, IChannel channel) => 92 | this.RunAsync(input, channel).Result; 93 | 94 | /// 95 | /// Simulates a function/operation using the OpenQasmExporter as target machine. 96 | /// It expects a single input: the name of the function/operation to simulate. 97 | /// 98 | /// current parameters for the function/operation. 99 | /// channel connecting up with jupiter. 100 | /// function result. 101 | public async Task RunAsync(string input, IChannel channel) 102 | { 103 | var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); 104 | 105 | var name = inputParameters.DecodeParameter(ParameterNameOperationName); 106 | var symbol = this.SymbolResolver.Resolve(name) as dynamic; // FIXME: should be as IQSharpSymbol. 107 | if (symbol == null) 108 | { 109 | throw new InvalidOperationException($"Invalid operation name: {name}"); 110 | } 111 | 112 | // TODO: File bug for the following to be public: 113 | // https://github.com/microsoft/iqsharp/blob/9fa7d4da4ec0401bf5803e40fce5b37e716c3574/src/Jupyter/ConfigurationSource.cs#L35 114 | var outputFileName = 115 | this.configurationSource.Configuration.TryGetValue("qasmexport.outputFileName", out var token) 116 | ? token.ToObject() 117 | : $"{name}.qasm"; 118 | 119 | channel.Display($"// Exporting to {outputFileName} (use %config qasmexport.outputFileName to change)"); 120 | 121 | using (var qsim = new Exporter(outputFileName, new ChannelTextWriter(channel))) 122 | { 123 | var operationInfo = (OperationInfo)symbol.Operation; 124 | var value = await operationInfo.RunAsync(qsim, inputParameters); 125 | 126 | return value.ToExecutionResult(); 127 | } 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /src/OpenQasmExporter/Intrinsics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.Quantum.Simulation.Core; 4 | using Intrinsic = Microsoft.Quantum.Intrinsic; 5 | 6 | namespace QSharpCommunity.Simulators.OpenQasmExporter.Circuits 7 | { 8 | public class Measure : Intrinsic.Measure 9 | { 10 | public Measure(IOperationFactory m) 11 | : base(m) { } 12 | 13 | public override Func<(IQArray, IQArray), Result> __Body__ => 14 | args => 15 | { 16 | var (bases, qubits) = args; 17 | foreach (var q in qubits) 18 | { 19 | Console.WriteLine($"measure q[{q.Id}] -> c[{q.Id}];"); 20 | } 21 | return Result.Zero; 22 | }; 23 | } 24 | 25 | // It's necessary to override this operation, so it doesn't end up in the OpenQASM output 26 | public class Message : Intrinsic.Message 27 | { 28 | public Message(IOperationFactory m) 29 | : base(m) { } 30 | 31 | public override Func __Body__ => 32 | msg => 33 | { 34 | // Ignore 35 | return QVoid.Instance; 36 | }; 37 | } 38 | 39 | // It's necessary to override this operation, so it doesn't end up in the OpenQASM output 40 | public class Reset : Intrinsic.Reset 41 | { 42 | public Reset(IOperationFactory m) 43 | : base(m) { } 44 | 45 | public override Func __Body__ => 46 | qubit => 47 | { 48 | return QVoid.Instance; 49 | }; 50 | } 51 | 52 | // It's necessary to override this operation, so it doesn't end up in the OpenQASM output 53 | public class ResetAll : Intrinsic.ResetAll 54 | { 55 | public ResetAll(IOperationFactory m) 56 | : base(m) { } 57 | 58 | public override Func, QVoid> __Body__ => 59 | args => 60 | { 61 | return QVoid.Instance; 62 | }; 63 | } 64 | 65 | public class SingleQubitOp : Intrinsic.I, ICallable 66 | { 67 | string ICallable.Name => typeof(T).Name; 68 | 69 | public override Func __Body__ => 70 | qubit => 71 | { 72 | var opName = ((ICallable)this).Name.ToLower(); 73 | Console.WriteLine($"{opName} q[{qubit.Id}];"); 74 | return QVoid.Instance; 75 | }; 76 | 77 | public override Func<(IQArray, Qubit), QVoid> __ControlledBody__ => 78 | args => 79 | { 80 | var (controls, qubit) = args; 81 | var controlCount = controls.Count; 82 | var controlPrefix = string.Concat(Enumerable.Repeat("c", controlCount)); 83 | var opName = ((ICallable)this).Name.ToLower(); 84 | Console.WriteLine($"{controlPrefix}{opName} {string.Join(",", controls.Select(c => $"q[{c.Id}]"))},q[{qubit.Id}];"); 85 | return QVoid.Instance; 86 | }; 87 | 88 | public override Func __AdjointBody__ => 89 | qubit => 90 | { 91 | var opName = ((ICallable)this).Name; 92 | switch (opName) 93 | { 94 | case nameof(Intrinsic.T): 95 | case nameof(Intrinsic.S): 96 | opName = opName.ToLower() +"dg"; 97 | break; 98 | 99 | default: 100 | opName = opName.ToLower(); 101 | break; 102 | } 103 | 104 | Console.WriteLine($"{opName} q[{qubit.Id}];"); 105 | return QVoid.Instance; 106 | }; 107 | 108 | public SingleQubitOp(IOperationFactory m) 109 | : base(m) {} 110 | } 111 | } -------------------------------------------------------------------------------- /src/OpenQasmExporter/OpenQasmExporter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | Library 6 | QsharpCommunity.Simulators.OpenQasmExporter 7 | 8 | https://qsharp.community/ 9 | MIT 10 | https://github.com/qsharp-community/qsharp-integrations.git 11 | git 12 | Copyright (c) Amir Ebrahimi. All rights reserved. Licensed under the MIT License. 13 | Export Q# functions or operations to OpenQasm 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/OpenQasmExporter/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qsharp-community/qsharp-integrations/34bb739a07c78dbaca0fadb968677afbe1169f2e/src/OpenQasmExporter/README.md -------------------------------------------------------------------------------- /src/OpenQasmReader/OpenQasmReader.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp3.1 5 | OpenQasmReader 6 | Microsoft.Quantum.Samples.OpenQasmReader 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/OpenQasmReader/Parser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.CompilerServices; 8 | using System.Text; 9 | 10 | //Export internal functions to able to test this class 11 | [assembly: InternalsVisibleTo("OpenQasmReader.Tests")] 12 | 13 | namespace Microsoft.Quantum.Samples.OpenQasmReader 14 | { 15 | /// 16 | /// A quick and simple qasm parser and Q# generator which was hand rolled to remain under MIT license 17 | /// 18 | public class Parser 19 | { 20 | /// 21 | /// Main runner 22 | /// Usage: Application 23 | /// 24 | /// 25 | public static void Main(string[] args) 26 | { 27 | if (args.Length != 2) 28 | { 29 | Console.WriteLine("QASM to Q# Conversion tool"); 30 | Console.WriteLine("Usage "); 31 | Console.WriteLine("Example: Quantum.Imported adder.qasm"); 32 | } 33 | else 34 | { 35 | Console.Write(ConvertQasmFile(args[0], args[1])); 36 | } 37 | } 38 | 39 | /// 40 | /// Convert the qasm file to Q# 41 | /// 42 | /// Namespace of the Q# to be under 43 | /// Path of the Qasm file 44 | /// Q# file content 45 | 46 | internal static string ConvertQasmFile(string ns, string path) 47 | { 48 | using (var file = File.OpenText(path)) 49 | { 50 | return ParseMain(Tokenizer(file).GetEnumerator(), ns, Path.GetFileNameWithoutExtension(path), Path.GetDirectoryName(path)); 51 | } 52 | } 53 | 54 | /// 55 | /// Parses the main qasm file 56 | /// Responsible for emitting the top method 57 | /// 58 | /// Current token of the tokenizer 59 | /// Namespace to generate the Q# file in 60 | /// Name of the file, which results in the operation name 61 | /// Directory the qasm is located in (mostly for include purposes) 62 | /// Q# file content 63 | private static string ParseMain(IEnumerator token, string ns, string name, string path) 64 | { 65 | var classicalMeasured = new List(); 66 | var qubitMeasured = new List(); 67 | var qRegs = new Dictionary(); 68 | var cRegs = new Dictionary(); 69 | var inside = new StringBuilder(); 70 | var outside = new StringBuilder(); 71 | IndentLevel += 4; 72 | ParseApplication(token, cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured); 73 | 74 | var result = new StringBuilder(inside.Length + outside.Length); 75 | result.AppendFormat(HEADER, ns); 76 | result.Append(outside.ToString()); 77 | WriteOperation(result, cRegs, qRegs, name, new string[] { }, classicalMeasured, qubitMeasured, inside); 78 | IndentLevel -= 4; 79 | result.Append(TAIL); 80 | return result.ToString(); 81 | } 82 | 83 | /// 84 | /// Parses the Qasm application and components 85 | /// 86 | /// Current token the tokenizer is on to parse 87 | /// Classical registers defined 88 | /// Quantum registers defined 89 | /// Directory the qasm is located in (mostly for include purposes) 90 | /// Stream to write within the current operation being parsed 91 | /// Stream to write outside the current operation being parsed (mostly for defining side operations) 92 | /// Currently measured classical registers (mostly used for output) 93 | /// Currently solo measured qubit (used for output) 94 | /// Process only one command 95 | internal static void ParseApplication(IEnumerator token, Dictionary cRegs, Dictionary qRegs, string path, StringBuilder inside, StringBuilder outside, List classicalMeasured, List qubitMeasured, bool stopAfterOneCommand = false) 96 | { 97 | while (token.MoveNext()) 98 | { 99 | switch (token.Current) 100 | { 101 | case "OPENQASM": 102 | ParseOpenQasmHeader(token); 103 | break; 104 | case "include": 105 | ParseInclude(token, cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured); 106 | break; 107 | //Intrinsic will take care of the optional native gates 108 | case "opaque": 109 | case "gate": 110 | ParseGateSpecification(token, path, outside); 111 | break; 112 | case "qreg": 113 | ParseQuantumRegister(token, qRegs); 114 | break; 115 | case "creg": 116 | ParseClassicalRegister(token, cRegs, inside); 117 | break; 118 | case "U": 119 | case "u": 120 | case "u3": 121 | ParseUGate(token, inside); 122 | break; 123 | case "u2": 124 | ParseU2Gate(token, inside); 125 | break; 126 | case "u1": 127 | ParseU1Gate(token, inside); 128 | break; 129 | case "x": 130 | case "X": 131 | ParseOneGate(token, "X", qRegs, inside); 132 | break; 133 | case "y": 134 | case "Y": 135 | ParseOneGate(token, "Y", qRegs, inside); 136 | break; 137 | case "z": 138 | case "Z": 139 | ParseOneGate(token, "Z", qRegs, inside); 140 | break; 141 | case "H": 142 | case "h": 143 | ParseOneGate(token, "H", qRegs, inside); 144 | break; 145 | case "s": 146 | ParseOneGate(token, "S", qRegs, inside); 147 | break; 148 | case "sdg": 149 | ParseOneGate(token, "Adjoint S", qRegs, inside); 150 | break; 151 | case "t": 152 | ParseOneGate(token, "T", qRegs, inside); 153 | break; 154 | case "tdg": 155 | ParseOneGate(token, "Adjoint T", qRegs, inside); 156 | break; 157 | case "barrier": 158 | ParseBarrier(token, qRegs); 159 | break; 160 | case "id": 161 | ParseOneGate(token, "I", qRegs, inside); 162 | break; 163 | case "CX": 164 | case "cx": 165 | case "Cx": 166 | ParseTwoGate(token, "CNOT", qRegs, inside); 167 | break; 168 | case "CRX": 169 | case "CRx": 170 | case "crx": 171 | ParseTwoParametricGate(token, "Rx", qRegs, inside); 172 | break; 173 | case "CZ": 174 | case "cz": 175 | case "Cz": 176 | ParseTwoGate(token, "CZ", qRegs, inside); 177 | break; 178 | case "CRZ": 179 | case "CRz": 180 | case "crz": 181 | ParseTwoParametricGate(token, "Rz", qRegs, inside); 182 | break; 183 | case "CY": 184 | case "cy": 185 | case "Cy": 186 | ParseTwoGate(token, "CY", qRegs, inside); 187 | break; 188 | case "CRY": 189 | case "CRy": 190 | case "cry": 191 | ParseTwoParametricGate(token, "Ry", qRegs, inside); 192 | break; 193 | case "ccx": 194 | ParseThreeGate(token, "CCNOT", qRegs, inside); 195 | break; 196 | case "CSWAP": 197 | case "CSwap": 198 | case "cswap": 199 | ParseThreeControlledGate(token, "SWAP", qRegs, inside); 200 | break; 201 | case "measure": 202 | ParseMeasure(token, inside, cRegs, qRegs, classicalMeasured, qubitMeasured); 203 | break; 204 | case "if": 205 | ParseIf(token, cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured); 206 | break; 207 | case CLOSE_CURLYBRACKET: 208 | return; 209 | case POINT_COMMA: 210 | if (stopAfterOneCommand) { return; } 211 | break; 212 | default: 213 | ParseGateCall(token, inside, qRegs); 214 | break; 215 | } 216 | if (stopAfterOneCommand && token.Current.Equals(POINT_COMMA)) { return; } 217 | } 218 | } 219 | 220 | /// 221 | /// Parse the if conditional 222 | /// 223 | /// Current token the tokenizer is on to parse 224 | /// Classical registers defined 225 | /// Quantum registers defined 226 | /// Directory the qasm is located in (mostly for include purposes) 227 | /// Stream to write within the current operation being parsed 228 | /// Stream to write outside the current operation being parsed (mostly for defining side operations) 229 | /// Currently measured classical registers (mostly used for output) 230 | /// Currently solo measured qubit (used for output) 231 | /// Process one command 232 | private static void ParseIf(IEnumerator token, Dictionary cRegs, Dictionary qRegs, string path, StringBuilder inside, StringBuilder outside, List classicalMeasured, List qubitMeasured) 233 | { 234 | token.MoveNext(); 235 | token.MoveNext(); 236 | var condition = ParseCondition(token, cRegs, CLOSE_PARENTHESES); 237 | Indent(inside); 238 | inside.AppendFormat("if({0}){{\n", condition); 239 | IndentLevel++; 240 | ParseApplication(token, cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured, true); 241 | IndentLevel--; 242 | Indent(inside); 243 | inside.AppendLine("}"); 244 | } 245 | 246 | /// 247 | /// Add indentation 248 | /// 249 | /// Current Stream 250 | private static void Indent(StringBuilder stream) 251 | { 252 | var indent = IndentLevel * INDENT; 253 | while (indent-- > 0) 254 | { 255 | stream.Append(' '); 256 | } 257 | } 258 | private static int IndentLevel { get; set; } 259 | 260 | /// 261 | /// Parses a condition statement 262 | /// 263 | /// current token 264 | /// traditional register 265 | /// current marker of an end 266 | /// The total condition statement 267 | internal static string ParseCondition(IEnumerator token, Dictionary cRegs, params string[] endmarker) 268 | { 269 | int depth = 0; 270 | string result = null; 271 | while (depth != 0 || !(endmarker.Any(marker => marker.Equals(token.Current)))) 272 | { 273 | if (token.Current.Equals(OPEN_PARENTHESES)) 274 | { 275 | depth++; 276 | result += token.Current; 277 | } 278 | else if (token.Current.Equals(CLOSE_PARENTHESES)) 279 | { 280 | depth--; 281 | result += token.Current; 282 | } 283 | else if (cRegs.ContainsKey(token.Current)) 284 | { 285 | result += string.Format("ResultAsInt({0})", token.Current); 286 | } 287 | else if (token.Current.Equals(PI)) 288 | { 289 | result += "PI()"; 290 | } 291 | else 292 | { 293 | result += token.Current; 294 | } 295 | if (!token.MoveNext()) { break; } 296 | } 297 | return result; 298 | } 299 | 300 | /// 301 | /// Register a classical (Result) register 302 | /// 303 | /// Current token the tokenizer is on to parse 304 | /// Classical registers defined 305 | /// Directory the qasm is located in (mostly for include purposes) 306 | private static void ParseClassicalRegister(IEnumerator token, Dictionary cRegs, StringBuilder inside) 307 | { 308 | token.MoveNext(); 309 | var name = token.Current; 310 | var index = name.IndexOf('[') + 1; 311 | var count = int.Parse(name.Substring(index, name.IndexOf(']') - index)); 312 | name = name.Remove(index - 1); 313 | cRegs.Add(name, count); 314 | 315 | token.MoveNext(); //; 316 | } 317 | 318 | private static void ParseQuantumRegister(IEnumerator token, Dictionary qRegs) 319 | { 320 | token.MoveNext(); 321 | var name = token.Current; 322 | var index = name.IndexOf('[') + 1; 323 | var count = int.Parse(name.Substring(index, name.IndexOf(']') - index)); 324 | qRegs.Add(name.Remove(index - 1), count); 325 | token.MoveNext(); //; 326 | } 327 | 328 | private static void ParseGateCall(IEnumerator token, StringBuilder builder, Dictionary qReg) 329 | { 330 | var gateName = token.Current; 331 | var doubles = new List(); 332 | var qubits = new List(); 333 | bool withinParentheses = false; 334 | while (token.MoveNext() && !token.Current.Equals(POINT_COMMA)) 335 | { 336 | if (token.Current.Equals(COMMA)) 337 | { 338 | continue; 339 | } 340 | else if (token.Current.Equals(CLOSE_PARENTHESES)) 341 | { 342 | withinParentheses = false; 343 | } 344 | else if (withinParentheses) 345 | { 346 | doubles.Add(ParseCalculation(token, $"{COMMA} ", CLOSE_PARENTHESES)); 347 | if (token.Current.Equals(CLOSE_PARENTHESES)) 348 | { 349 | withinParentheses = false; 350 | } 351 | } 352 | else if (token.Current.Equals(OPEN_PARENTHESES)) 353 | { 354 | withinParentheses = true; 355 | } 356 | else 357 | { 358 | qubits.Add(token.Current); 359 | } 360 | } 361 | 362 | var loopRequired = qReg.Count != 0 && qubits.Any() && !qubits.Any(q => q.Contains('[')); 363 | if (loopRequired) 364 | { 365 | Indent(builder); 366 | var size = qubits.First(q => !q.Contains('[')); 367 | builder.AppendFormat("for _idx in 0 .. Length({0}) - 1 {{\n", size); 368 | IndentLevel++; 369 | } 370 | Indent(builder); 371 | builder.Append(FirstLetterToUpperCase(gateName)); 372 | builder.Append('('); 373 | var types = doubles.Concat(qubits.Select(qubit => IndexedCall(qubit, qubit.Contains('[')))); 374 | builder.Append(string.Join($"{COMMA} ", types)); 375 | builder.AppendLine(");"); 376 | if (loopRequired) 377 | { 378 | IndentLevel--; 379 | Indent(builder); 380 | builder.AppendLine("}"); 381 | } 382 | } 383 | 384 | internal static void ParseBarrier(IEnumerator token, Dictionary qReg) 385 | { 386 | //Ignore, because its by default in Q# 387 | while (token.MoveNext() && !token.Current.Equals(POINT_COMMA)) { } 388 | } 389 | 390 | private static void ParseOneGate(IEnumerator token, string gate, Dictionary qReg, StringBuilder builder) 391 | { 392 | token.MoveNext(); 393 | var q1 = token.Current; 394 | token.MoveNext(); // ; 395 | Indent(builder); 396 | if (qReg.Count == 0 || q1.Contains('[')) 397 | { 398 | builder.AppendFormat("{0}({1});\n", gate, q1); 399 | } 400 | //Implicit expansion 401 | else 402 | { 403 | builder.AppendFormat("ApplyToEach({0}, {1});\n", gate, q1); 404 | } 405 | } 406 | 407 | private static void ParseTwoGate(IEnumerator token, string gate, Dictionary qReg, StringBuilder builder) 408 | { 409 | token.MoveNext(); 410 | var leftQubit = token.Current; 411 | token.MoveNext(); // , 412 | token.MoveNext(); 413 | var rightQubit = token.Current; 414 | token.MoveNext(); // ; 415 | Indent(builder); 416 | if (qReg.Count == 0 || (leftQubit.Contains('[') && rightQubit.Contains('['))) 417 | { 418 | builder.AppendFormat("{0}({1}, {2});\n", gate, leftQubit, rightQubit); 419 | } 420 | else 421 | { 422 | var index = leftQubit.IndexOf('['); 423 | var size = index < 0 ? leftQubit : leftQubit.Remove(index); 424 | builder.AppendFormat("for _idx in 0 .. Length({0}) - 1 {{\n", size); 425 | IndentLevel++; 426 | Indent(builder); 427 | builder.AppendFormat("{0}({1}, {2});\n", gate, 428 | IndexedCall(leftQubit, true), 429 | IndexedCall(rightQubit, true)); 430 | IndentLevel--; 431 | Indent(builder); 432 | builder.AppendLine("}"); 433 | } 434 | } 435 | 436 | private static void ParseTwoParametricGate(IEnumerator token, string gate, Dictionary qReg, StringBuilder builder) 437 | { 438 | token.MoveNext(); // ( 439 | token.MoveNext(); 440 | var angle = token.Current; 441 | token.MoveNext(); // ) 442 | token.MoveNext(); 443 | var leftQubit = token.Current; 444 | token.MoveNext(); // , 445 | token.MoveNext(); 446 | var rightQubit = token.Current; 447 | token.MoveNext(); // ; 448 | Indent(builder); 449 | builder.AppendFormat("Controlled {0}([{1}], ({2}, {3}));\n", gate, leftQubit, angle, rightQubit); 450 | } 451 | 452 | /// 453 | /// Parse a measure gate 454 | /// 455 | /// Current token the tokenizer is on to parse 456 | /// Classical registers defined 457 | /// Stream to write within the current operation being parsed 458 | /// Quantum registers defined 459 | /// Currently measured classical registers (mostly used for output) 460 | /// Currently solo measured qubit (used for output) 461 | private static void ParseMeasure(IEnumerator token, StringBuilder builder, Dictionary cReg, Dictionary qReg, List classicalMeasured, List qubitMeasured) 462 | { 463 | token.MoveNext(); 464 | var q1 = token.Current; 465 | token.MoveNext(); // - 466 | if (POINT_COMMA.Equals(token.Current)) //Implicit measure 467 | { 468 | var loopRequired = qReg.Count != 0 && !q1.Contains('['); 469 | if (loopRequired) //implicit Expansion 470 | { 471 | Indent(builder); 472 | var size = qReg[q1]; 473 | for (int i = 0; i < size; i++) 474 | { 475 | Indent(builder); 476 | builder.AppendFormat("set _out w/= {0} <- M({1}[{2}]);\n", i, q1, i); 477 | qubitMeasured.Add(q1 + $"[{i}]"); 478 | } 479 | } 480 | else 481 | { 482 | Indent(builder); 483 | builder.AppendFormat("set _out w/= {0} <- M({1});\n", qubitMeasured.Count, q1); 484 | qubitMeasured.Add(q1); 485 | } 486 | } 487 | else //Explicit measure 488 | { 489 | token.MoveNext(); // > 490 | token.MoveNext(); 491 | var q3 = token.Current; 492 | token.MoveNext(); // 493 | 494 | var loopRequired = qReg.Count != 0 && !(q1.Contains('[') && q3.Contains('[')); 495 | if (loopRequired) 496 | { 497 | Indent(builder); 498 | var index = q1.IndexOf('['); 499 | var size = index < 0 ? q3 : q1.Remove(index); 500 | builder.AppendFormat("for _idx in 0 .. Length({0}) - 1 {{\n", size); 501 | IndentLevel++; 502 | } 503 | Indent(builder); 504 | builder.AppendFormat("set {0} <- M({1});\n", IndexedCall(q3, loopRequired, true), IndexedCall(q1, loopRequired)); 505 | if (loopRequired) 506 | { 507 | IndentLevel--; 508 | Indent(builder); 509 | builder.AppendLine("}"); 510 | } 511 | 512 | if (q3.Contains('[')) 513 | { 514 | if (!classicalMeasured.Contains(q3)) { classicalMeasured.Add(q3); } 515 | } 516 | else 517 | { 518 | //implicit Expansion 519 | var index = q3.IndexOf('['); 520 | var size = index < 0 ? q3 : q3.Remove(index); 521 | var count = cReg[size]; 522 | for (int i = 0; i < count; i++) 523 | { 524 | var name = string.Format("{0}[{1}]", size, i); 525 | if (!classicalMeasured.Contains(name)) { classicalMeasured.Add(name); } 526 | } 527 | } 528 | } 529 | } 530 | 531 | /// 532 | /// Parse a gate with three Qubits (e.g. CCNOT) 533 | /// 534 | /// Gate being parsed 535 | /// Current token the tokenizer is on to parse 536 | /// Stream to write within the current operation being parsed 537 | /// Quantum registers defined 538 | private static void ParseThreeGate(IEnumerator token, string gate, Dictionary qReg, StringBuilder builder) 539 | { 540 | token.MoveNext(); 541 | var q1 = token.Current; 542 | token.MoveNext(); // , 543 | token.MoveNext(); 544 | var q2 = token.Current; 545 | token.MoveNext(); // , 546 | token.MoveNext(); 547 | var q3 = token.Current; 548 | token.MoveNext(); // 549 | Indent(builder); 550 | var loopRequired = qReg.Count != 0 && !((q1.Contains('[') && q2.Contains('[') && q3.Contains('['))); 551 | if (loopRequired) 552 | { 553 | Indent(builder); 554 | var index = q1.IndexOf('['); 555 | var size = index < 0 ? q3 : q1.Remove(index); 556 | builder.AppendFormat("for _idx in 0 .. Length({0}) - 1 {{\n", size); 557 | IndentLevel++; 558 | } 559 | builder.AppendFormat("{0}({1}, {2}, {3});\n", gate, 560 | IndexedCall(q1, loopRequired), 561 | IndexedCall(q2, loopRequired), 562 | IndexedCall(q3, loopRequired)); 563 | if (loopRequired) 564 | { 565 | IndentLevel--; 566 | Indent(builder); 567 | builder.AppendLine("}"); 568 | } 569 | } 570 | 571 | private static void ParseThreeControlledGate(IEnumerator token, string gate, Dictionary qReg, StringBuilder builder) 572 | { 573 | token.MoveNext(); 574 | var controlQubit = token.Current; 575 | token.MoveNext(); // , 576 | token.MoveNext(); 577 | var targetQubit1 = token.Current; 578 | token.MoveNext(); // , 579 | token.MoveNext(); 580 | var targetQubit2 = token.Current; 581 | token.MoveNext(); // ; 582 | Indent(builder); 583 | builder.AppendFormat("Controlled {0}([{1}], ({2}, {3}));\n", gate, controlQubit, targetQubit1, targetQubit2); 584 | } 585 | 586 | /// 587 | /// Makes a reference to a register an indexed reference if we need a loop 588 | /// OpenQasm has implicit loops, which Q# needs to be explicit 589 | /// 590 | /// Register name 591 | /// 592 | /// 593 | internal static string IndexedCall(string name, bool loopRequired, bool forAssignment = false) 594 | { 595 | return !loopRequired || name.Contains('[') ? forAssignment ? name.Replace("[", " w/= ").Replace("]","") : name : 596 | forAssignment ? $"{name} w/= _idx" : $"{name}[_idx]"; 597 | } 598 | 599 | /// 600 | /// Only checking the header 601 | /// 602 | /// Current token the tokenizer is on to parse 603 | internal static void ParseOpenQasmHeader(IEnumerator token) 604 | { 605 | token.MoveNext(); //2.0 606 | if (!token.Current.Equals("2.0")) 607 | { 608 | Console.Error.WriteLine($"//Parser has been written for version 2.0. Found version {token.Current}. Results may be incorrect."); 609 | }; 610 | token.MoveNext(); //; 611 | } 612 | 613 | /// 614 | /// Intrinsic gates of Q# 615 | /// 616 | private readonly static HashSet Intrinsic = new HashSet() 617 | { 618 | "id", "barrier", 619 | "h", "x", "y", "z", "s", "t", 620 | "sdg", "tdg", 621 | "cx", "ccx", 622 | "measure", 623 | "u1","u3" 624 | }; 625 | 626 | /// 627 | /// Parses a gate (and opaque gate) definition 628 | /// 629 | /// Current token the tokenizer is on to parse 630 | /// Directory the qasm is located in (mostly for include purposes) 631 | /// Stream to write outside the current operation being parsed (mostly for defining side operations) 632 | private static void ParseGateSpecification(IEnumerator token, string path, StringBuilder outside) 633 | { 634 | token.MoveNext(); 635 | var gateName = token.Current; 636 | if (Intrinsic.Contains(gateName)) 637 | { 638 | while (token.MoveNext() && !token.Current.Equals(CLOSE_CURLYBRACKET)) { } 639 | return; 640 | } 641 | 642 | var doubles = new List(); 643 | var qubits = new List(); 644 | bool withinParentheses = false; 645 | while (token.MoveNext() && !token.Current.Equals(OPEN_CURLYBRACKET)) 646 | { 647 | if (token.Current.Equals(COMMA)) 648 | { 649 | continue; 650 | } 651 | else if (token.Current.Equals(CLOSE_PARENTHESES)) 652 | { 653 | withinParentheses = false; 654 | } 655 | else if (withinParentheses) 656 | { 657 | doubles.Add(ParseCalculation(token, COMMA, CLOSE_PARENTHESES)); 658 | if (token.Current.Equals(CLOSE_PARENTHESES)) 659 | { 660 | withinParentheses = false; 661 | } 662 | } 663 | else if (token.Current.Equals(OPEN_PARENTHESES)) 664 | { 665 | withinParentheses = true; 666 | } 667 | else 668 | { 669 | qubits.Add(token.Current); 670 | } 671 | } 672 | var types = doubles.Select(d => string.Format("{0} : Double", d)) 673 | .Concat(qubits.Select(qubit => string.Format("{0} : Qubit", qubit))); 674 | var classicalMeasured = new List(); 675 | var qubitMeasured = new List(); 676 | var inside = new StringBuilder(); 677 | var qRegs = new Dictionary(); 678 | var cRegs = new Dictionary(); 679 | ParseApplication(token, cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured); 680 | WriteOperation(outside, cRegs, qRegs, gateName, types, classicalMeasured, qubitMeasured, inside); 681 | } 682 | 683 | /// 684 | /// Returns the input string with the first character converted to uppercase, or mutates any nulls passed into string.Empty 685 | /// 686 | /// Current string to be converted 687 | /// Same string with the first letter capitalized (or an empty string if not possible) 688 | internal static string FirstLetterToUpperCase(string s) 689 | { 690 | if (string.IsNullOrEmpty(s)) 691 | { 692 | return string.Empty; 693 | } 694 | 695 | char[] a = s.ToCharArray(); 696 | a[0] = char.ToUpper(a[0]); 697 | return new string(a); 698 | } 699 | 700 | /// 701 | /// Write the Q# operation with all the details 702 | /// 703 | /// Current token the tokenizer is on to parse 704 | /// Classical registers defined 705 | /// Quantum registers defined 706 | /// Directory the qasm is located in (mostly for include purposes) 707 | /// Stream to write within the current operation being parsed 708 | /// Stream to write outside the current operation being parsed (mostly for defining side operations) 709 | /// Currently measured classical registers (mostly used for output) 710 | /// Currently solo measured qubit (used for output) 711 | /// The intended name of the operation 712 | /// Parameters of this operation (mostly used for gates) 713 | private static void WriteOperation(StringBuilder outside, Dictionary cRegs, Dictionary qRegs, string operationName, IEnumerable types, List classicalMeasured, List qubitMeasured, StringBuilder inside) 714 | { 715 | outside.AppendFormat(HEADER_OPERATION, FirstLetterToUpperCase(operationName), string.Join(", ", types), classicalMeasured.Any() || qubitMeasured.Any() ? "Result[]" : "Unit"); 716 | 717 | if (qRegs.Any()) 718 | { 719 | //Move indentation a bit back 720 | IndentLevel--; 721 | } 722 | 723 | if (qubitMeasured.Any()) 724 | { 725 | Indent(outside); 726 | outside.AppendLine($"mutable _out = new Result[{qubitMeasured.Count}];"); 727 | } 728 | if (cRegs.Any()) 729 | { 730 | foreach (var cRegister in cRegs) 731 | { 732 | Indent(outside); 733 | outside.AppendFormat("mutable {0} = new Result[{1}];\n", cRegister.Key, cRegister.Value); 734 | } 735 | } 736 | 737 | if (qRegs.Any()) 738 | { 739 | foreach (var qubitRegister in qRegs) 740 | { 741 | Indent(outside); 742 | outside.AppendFormat("use {0} = Qubit[{1}];\n", qubitRegister.Key, qubitRegister.Value); 743 | } 744 | } 745 | outside.Append(inside.ToString()); 746 | if (qRegs.Any()) 747 | { 748 | foreach (var qubitRegister in qRegs) 749 | { 750 | Indent(outside); 751 | outside.AppendFormat("ResetAll({0});\n", qubitRegister.Key); 752 | } 753 | } 754 | if (classicalMeasured.Any() || qubitMeasured.Any()) 755 | { 756 | Indent(outside); 757 | var result = Enumerable.Range(0, qubitMeasured.Count).Select(n => $"_out[{n}]") 758 | .Concat(classicalMeasured); 759 | outside.AppendFormat("return [{0}];\n", string.Join($"{COMMA} ", result)); 760 | } 761 | if (qRegs.Any()) 762 | { 763 | IndentLevel++; 764 | } 765 | outside.AppendLine(TAIL_OPERATION); 766 | } 767 | 768 | /// 769 | /// Parse an U1 Gate which is a one axis rotation 770 | /// 771 | /// Current token the tokenizer is on to parse 772 | /// 773 | private static void ParseU1Gate(IEnumerator token, StringBuilder builder) 774 | { 775 | token.MoveNext(); //( 776 | token.MoveNext(); 777 | var theta = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 778 | token.MoveNext(); 779 | var q = token.Current; 780 | token.MoveNext(); // ; 781 | if (!theta.Equals(ZERO)) 782 | { 783 | Indent(builder); 784 | builder.AppendFormat("R1({0}, {1});\n", theta, q); 785 | } 786 | else 787 | { 788 | // 0,0,0 rotation is the idle 789 | // Could have left it out, but people seem to use this as a first test and are surprised when it gets optimized away. 790 | Indent(builder); 791 | builder.AppendFormat("I({0});\n", q); 792 | } 793 | } 794 | 795 | /// 796 | /// Parse a U2 Gate which is a single qubit rotation 797 | /// 798 | /// Current token the tokenizer is on to parse 799 | /// 800 | private static void ParseU2Gate(IEnumerator token, StringBuilder builder) 801 | { 802 | token.MoveNext(); //( 803 | token.MoveNext(); 804 | var phi = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 805 | token.MoveNext(); 806 | var lambda = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 807 | token.MoveNext(); 808 | var q = token.Current; 809 | token.MoveNext(); // ; 810 | if (!phi.Equals(ZERO)) 811 | { 812 | Indent(builder); 813 | builder.AppendFormat("Rz({0}, {1});\n", phi, q); 814 | } 815 | Indent(builder); 816 | builder.AppendFormat("Ry(PI() / 2.0, {0});\n", q); 817 | if (!lambda.Equals(ZERO)) 818 | { 819 | Indent(builder); 820 | builder.AppendFormat("Rz({0}, {1});\n", lambda, q); 821 | } 822 | if (!phi.Equals(ZERO) || !lambda.Equals(ZERO)) 823 | { 824 | Indent(builder); 825 | builder.AppendFormat("R(PauliI, -({0} + {1}), {2});\n", phi, lambda, q); 826 | } 827 | } 828 | 829 | /// 830 | /// Parse an U Gate which is a three axis rotation 831 | /// 832 | /// Current token the tokenizer is on to parse 833 | /// 834 | private static void ParseUGate(IEnumerator token, StringBuilder builder) 835 | { 836 | token.MoveNext(); //( 837 | token.MoveNext(); 838 | var theta = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 839 | token.MoveNext(); 840 | var phi = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 841 | token.MoveNext(); 842 | var lambda = ParseCalculation(token, COMMA, CLOSE_PARENTHESES); 843 | token.MoveNext(); 844 | var q = token.Current; 845 | token.MoveNext(); // ; 846 | bool written = false; 847 | if (!lambda.Equals(ZERO)) 848 | { 849 | written = true; 850 | Indent(builder); 851 | builder.AppendFormat("Rz({0}, {1});\n", lambda, q); 852 | } 853 | if (!theta.Equals(ZERO)) 854 | { 855 | written = true; 856 | Indent(builder); 857 | builder.AppendFormat("Ry({0}, {1});\n", theta, q); 858 | } 859 | if (!phi.Equals(ZERO)) 860 | { 861 | written = true; 862 | Indent(builder); 863 | builder.AppendFormat("Rz({0}, {1});\n", phi, q); 864 | } 865 | if (!phi.Equals(ZERO) || !lambda.Equals(ZERO)) 866 | { 867 | written = true; 868 | Indent(builder); 869 | builder.AppendFormat("R(PauliI, -({0} + {1}), {2});\n", phi, lambda, q); 870 | } 871 | if (!written) 872 | { 873 | // 0,0,0 rotation is the idle 874 | // Could have left it out, but people seem to use this as a first test and are surprised when it gets optimized away. 875 | Indent(builder); 876 | builder.AppendFormat("I({0});\n", q); 877 | } 878 | } 879 | 880 | /// 881 | /// Parse a value, which can be a calculation or formula 882 | /// 883 | /// Current token the tokenizer is on to parse 884 | /// Marker to denote what to stop on 885 | /// The value or concatenated formula 886 | internal static string ParseCalculation(IEnumerator token, params string[] endmarker) 887 | { 888 | int depth = 0; 889 | string result = null; 890 | while (depth != 0 || !(endmarker.Any(marker => marker.Equals(token.Current)))) 891 | { 892 | if (token.Current.Equals(OPEN_PARENTHESES)) 893 | { 894 | depth++; 895 | result += token.Current; 896 | } 897 | else if (token.Current.Equals(CLOSE_PARENTHESES)) 898 | { 899 | depth--; 900 | result += token.Current; 901 | } 902 | else if (token.Current.Equals(PI)) 903 | { 904 | result += "PI()"; 905 | } 906 | else if (token.Current.All(c => char.IsDigit(c))) 907 | { 908 | result += token.Current + ".0"; 909 | } 910 | //Scientific value 911 | else if (char.IsDigit(token.Current[0]) && token.Current.Last() == 'e') 912 | { 913 | result += token.Current; 914 | token.MoveNext(); 915 | result += token.Current; 916 | token.MoveNext(); 917 | result += token.Current; 918 | } 919 | else 920 | { 921 | result += token.Current; 922 | } 923 | if (!token.MoveNext()) { break; } 924 | } 925 | return result; 926 | } 927 | 928 | /// 929 | /// Parses the include statement 930 | /// Its not really clear by the specification, but an include may be anywhere in line and inject gates within an operation. 931 | /// 932 | /// Current token the tokenizer is on to parse 933 | /// Classical registers defined 934 | /// Quantum registers defined 935 | /// Directory the qasm is located in (mostly for include purposes) 936 | /// Stream to write within the current operation being parsed 937 | /// Stream to write outside the current operation being parsed (mostly for defining side operations) 938 | /// Currently measured classical registers (mostly used for output) 939 | /// Currently solo measured qubit (used for output) 940 | internal static void ParseInclude(IEnumerator token, Dictionary cRegs, Dictionary qRegs, string path, StringBuilder inside, StringBuilder outside, List classicalMeasured, List qubitMeasured) 941 | { 942 | if (token.MoveNext()) 943 | { 944 | var fileName = token.Current; 945 | while (token.MoveNext() && !token.Current.Equals(POINT_COMMA)) 946 | { 947 | fileName += token.Current; 948 | } 949 | 950 | var fullFileName = Path.Combine(path, fileName); 951 | if (File.Exists(fullFileName)) 952 | { 953 | using (var stream = File.OpenText(fullFileName)) 954 | { 955 | ParseApplication(Tokenizer(stream).GetEnumerator(), cRegs, qRegs, path, inside, outside, classicalMeasured, qubitMeasured); 956 | } 957 | } 958 | //Some people use qelib1.inc or other include of a template but don't actually have the file or use it 959 | //So if the file is not there, just give a warning in the output and continue 960 | else 961 | { 962 | outside.AppendLine($"//The file {fileName} to be included in the QASM was not found. Generated without it."); 963 | } 964 | } 965 | else 966 | { 967 | throw new Exception($"Unexpected end after include"); 968 | } 969 | } 970 | 971 | /// 972 | /// Tokenizer to split the stream of the file up in individual tokens 973 | /// 974 | /// Filestream 975 | /// Tokens in the code file 976 | internal static IEnumerable Tokenizer(TextReader stream) 977 | { 978 | var token = new StringBuilder(); 979 | var buffer = new char[1]; 980 | 981 | while (stream.ReadBlock(buffer, 0, 1) == 1) 982 | { 983 | if (buffer[0] == '/') 984 | { 985 | if (stream.ReadBlock(buffer, 0, 1) == 1) 986 | { 987 | //comment block 988 | if (buffer[0] == '/') 989 | { 990 | //ignore rest of line 991 | while (stream.ReadBlock(buffer, 0, 1) == 1 && buffer[0] != '\n') ; 992 | } 993 | // part of formula 994 | else 995 | { 996 | //flush current token 997 | if (token.Length != 0) 998 | { 999 | yield return token.ToString(); 1000 | token.Clear(); 1001 | } 1002 | yield return FORWARD_SLASH; 1003 | //Handle the character after the slash 1004 | if (char.IsLetterOrDigit(buffer[0]) || buffer[0] == '_' || buffer[0] == '.' || buffer[0] == '[' || buffer[0] == ']') 1005 | { 1006 | token.Append(buffer[0]); 1007 | } 1008 | else 1009 | { 1010 | switch (buffer[0]) 1011 | { 1012 | case '(': yield return OPEN_PARENTHESES; break; 1013 | case ')': yield return CLOSE_PARENTHESES; break; 1014 | case '{': yield return OPEN_CURLYBRACKET; break; 1015 | case '}': yield return CLOSE_CURLYBRACKET; break; 1016 | case ',': yield return COMMA; break; 1017 | case ';': yield return POINT_COMMA; break; 1018 | case '+': yield return PLUS; break; 1019 | case '-': yield return MINUS; break; 1020 | case '*': yield return STAR; break; 1021 | case '=': yield return IS; break; 1022 | case '!': yield return NOT; break; 1023 | case '<': yield return LT; break; 1024 | case '>': yield return MT; break; 1025 | default: 1026 | //ignore 1027 | break; 1028 | } 1029 | } 1030 | } 1031 | } 1032 | else 1033 | { 1034 | throw new Exception("Unexpected end of file"); 1035 | } 1036 | } 1037 | else if (char.IsLetterOrDigit(buffer[0]) || buffer[0] == '_' || buffer[0] == '.' || buffer[0] == '[' || buffer[0] == ']') 1038 | { 1039 | token.Append(buffer[0]); 1040 | } 1041 | else 1042 | { 1043 | if (token.Length != 0) 1044 | { 1045 | yield return token.ToString(); 1046 | token.Clear(); 1047 | } 1048 | switch (buffer[0]) 1049 | { 1050 | case '(': yield return OPEN_PARENTHESES; break; 1051 | case ')': yield return CLOSE_PARENTHESES; break; 1052 | case '{': yield return OPEN_CURLYBRACKET; break; 1053 | case '}': yield return CLOSE_CURLYBRACKET; break; 1054 | case ',': yield return COMMA; break; 1055 | case ';': yield return POINT_COMMA; break; 1056 | case '+': yield return PLUS; break; 1057 | case '-': yield return MINUS; break; 1058 | case '*': yield return STAR; break; 1059 | case '=': yield return IS; break; 1060 | case '!': yield return NOT; break; 1061 | case '<': yield return LT; break; 1062 | case '>': yield return MT; break; 1063 | default: 1064 | //ignore 1065 | break; 1066 | } 1067 | } 1068 | } 1069 | if (token.Length != 0) 1070 | { 1071 | yield return token.ToString(); 1072 | } 1073 | } 1074 | 1075 | #region Tokens and other constant Strings 1076 | private const string OPEN_PARENTHESES = "("; 1077 | private const string FORWARD_SLASH = "/"; 1078 | private const string OPEN_CURLYBRACKET = "{"; 1079 | private const string CLOSE_PARENTHESES = ")"; 1080 | private const string CLOSE_CURLYBRACKET = "}"; 1081 | private const string COMMA = ","; 1082 | private const string POINT_COMMA = ";"; 1083 | private const string PLUS = "+"; 1084 | private const string MINUS = "-"; 1085 | private const string STAR = "*"; 1086 | private const string IS = "="; 1087 | private const string NOT = "!"; 1088 | private const string LT = "<"; 1089 | private const string MT = ">"; 1090 | private const string PI = "pi"; 1091 | private const string ZERO = "0.0"; 1092 | private const string HEADER = 1093 | @"namespace {0} 1094 | {{ 1095 | open Microsoft.Quantum.Intrinsic; 1096 | open Microsoft.Quantum.Canon; 1097 | open Microsoft.Quantum.Math; 1098 | "; 1099 | private const string HEADER_OPERATION = 1100 | @" 1101 | operation {0} ({1}) : {2} 1102 | {{ 1103 | "; 1104 | private const string TAIL_OPERATION = 1105 | @" }"; 1106 | private const string TAIL = @"}"; 1107 | //Four spaces 1108 | internal const int INDENT = 4; 1109 | #endregion 1110 | } 1111 | 1112 | } 1113 | -------------------------------------------------------------------------------- /src/OpenQasmReader/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qsharp-community/qsharp-integrations/34bb739a07c78dbaca0fadb968677afbe1169f2e/src/OpenQasmReader/README.md -------------------------------------------------------------------------------- /tests/OpenQasmExporter.Sample/OpenQasmExporter.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Exe 10 | netcoreapp3.1 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/OpenQasmExporter.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace OpenQasmExporter.Sample 5 | { 6 | class Program 7 | { 8 | static async Task Main(string[] args) 9 | { 10 | Console.WriteLine("Exporting Test.qs"); 11 | using (var exporter = new QSharpCommunity.Simulators.OpenQasmExporter.Exporter("Test.qasm")) 12 | { 13 | await Tests.SampleTest.Run(exporter); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/OpenQasmExporter.Sample/SampleExporterMagic.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "application/json": "{\"LastUpdated\":\"2020-07-31T17:24:58.6543426-07:00\",\"IsCompleted\":true,\"Description\":\"Adding package QsharpCommunity.Simulators.OpenQasmExporter::1.0.0\",\"Subtask\":\"done\"}", 11 | "text/plain": [ 12 | "Adding package QsharpCommunity.Simulators.OpenQasmExporter::1.0.0: done!" 13 | ] 14 | }, 15 | "metadata": {}, 16 | "output_type": "display_data" 17 | }, 18 | { 19 | "data": { 20 | "application/json": "[\"Microsoft.Quantum.Standard::0.12.20072031\",\"QsharpCommunity.Simulators.OpenQasmExporter::1.0.0\"]", 21 | "text/html": [ 22 | "
  • Microsoft.Quantum.Standard::0.12.20072031
  • QsharpCommunity.Simulators.OpenQasmExporter::1.0.0
" 23 | ], 24 | "text/plain": [ 25 | "Microsoft.Quantum.Standard::0.12.20072031, QsharpCommunity.Simulators.OpenQasmExporter::1.0.0" 26 | ] 27 | }, 28 | "execution_count": 1, 29 | "metadata": {}, 30 | "output_type": "execute_result" 31 | } 32 | ], 33 | "source": [ 34 | "%package QsharpCommunity.Simulators.OpenQasmExporter::1.0.0" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "metadata": {}, 41 | "outputs": [ 42 | { 43 | "data": { 44 | "application/json": "[]", 45 | "text/html": [ 46 | "
    " 47 | ], 48 | "text/plain": [] 49 | }, 50 | "execution_count": 2, 51 | "metadata": {}, 52 | "output_type": "execute_result" 53 | } 54 | ], 55 | "source": [ 56 | "open Microsoft.Quantum.Measurement;" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 3, 62 | "metadata": {}, 63 | "outputs": [ 64 | { 65 | "data": { 66 | "application/json": "[\"foo\"]", 67 | "text/html": [ 68 | "
    • foo
    " 69 | ], 70 | "text/plain": [ 71 | "foo" 72 | ] 73 | }, 74 | "execution_count": 3, 75 | "metadata": {}, 76 | "output_type": "execute_result" 77 | } 78 | ], 79 | "source": [ 80 | "operation foo() : Result {\n", 81 | " using (register = Qubit[4]) {\n", 82 | " H(register[2]); //|+>\n", 83 | " S(register[2]); //|i>\n", 84 | " S(register[2]); //|->\n", 85 | " H(register[2]); //|1>\n", 86 | " return MResetZ(register[2]);\n", 87 | " }\n", 88 | "} " 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 4, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "data": { 98 | "application/json": "1", 99 | "text/plain": [ 100 | "One" 101 | ] 102 | }, 103 | "execution_count": 4, 104 | "metadata": {}, 105 | "output_type": "execute_result" 106 | } 107 | ], 108 | "source": [ 109 | "%simulate foo" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 5, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "application/json": "\"// Exporting to foo.qasm (use %config qasmexport.outputFileName to change)\"", 120 | "text/plain": [ 121 | "// Exporting to foo.qasm (use %config qasmexport.outputFileName to change)" 122 | ] 123 | }, 124 | "metadata": {}, 125 | "output_type": "display_data" 126 | }, 127 | { 128 | "name": "stdout", 129 | "output_type": "stream", 130 | "text": [ 131 | "OPENQASM 2.0;\n", 132 | "include \"qelib1.inc\";\n", 133 | "qreg q[32];\n", 134 | "creg c[32];\n", 135 | "h q[2];\n", 136 | "s q[2];\n", 137 | "s q[2];\n", 138 | "h q[2];\n", 139 | "measure q[2] -> c[2];\n" 140 | ] 141 | }, 142 | { 143 | "data": { 144 | "application/json": "0", 145 | "text/plain": [ 146 | "Zero" 147 | ] 148 | }, 149 | "execution_count": 5, 150 | "metadata": {}, 151 | "output_type": "execute_result" 152 | } 153 | ], 154 | "source": [ 155 | "%qasmexport foo" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 6, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "application/json": "\"\\\"bar.qasm\\\"\"", 166 | "text/plain": [ 167 | "\"bar.qasm\"" 168 | ] 169 | }, 170 | "execution_count": 6, 171 | "metadata": {}, 172 | "output_type": "execute_result" 173 | } 174 | ], 175 | "source": [ 176 | "%config qasmexport.outputFileName = \"bar.qasm\"" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 7, 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "data": { 186 | "application/json": "{\"rows\":[{\"Key\":\"qasmexport.outputFileName\",\"Value\":\"bar.qasm\"}]}", 187 | "text/html": [ 188 | "
    Configuration keyValue
    qasmexport.outputFileName\"bar.qasm\"
    " 189 | ], 190 | "text/plain": [ 191 | "Configuration key Value\r\n", 192 | "------------------------- ----------\r\n", 193 | "qasmexport.outputFileName \"bar.qasm\"\r\n" 194 | ] 195 | }, 196 | "execution_count": 7, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "%config" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 8, 208 | "metadata": {}, 209 | "outputs": [ 210 | { 211 | "data": { 212 | "application/json": "\"// Exporting to bar.qasm (use %config qasmexport.outputFileName to change)\"", 213 | "text/plain": [ 214 | "// Exporting to bar.qasm (use %config qasmexport.outputFileName to change)" 215 | ] 216 | }, 217 | "metadata": {}, 218 | "output_type": "display_data" 219 | }, 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "OPENQASM 2.0;\n", 225 | "include \"qelib1.inc\";\n", 226 | "qreg q[32];\n", 227 | "creg c[32];\n", 228 | "h q[2];\n", 229 | "s q[2];\n", 230 | "s q[2];\n", 231 | "h q[2];\n", 232 | "measure q[2] -> c[2];\n" 233 | ] 234 | }, 235 | { 236 | "data": { 237 | "application/json": "0", 238 | "text/plain": [ 239 | "Zero" 240 | ] 241 | }, 242 | "execution_count": 8, 243 | "metadata": {}, 244 | "output_type": "execute_result" 245 | } 246 | ], 247 | "source": [ 248 | "%qasmexport foo" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": null, 254 | "metadata": {}, 255 | "outputs": [], 256 | "source": [] 257 | } 258 | ], 259 | "metadata": { 260 | "kernelspec": { 261 | "display_name": "Q#", 262 | "language": "qsharp", 263 | "name": "iqsharp" 264 | }, 265 | "language_info": { 266 | "file_extension": ".qs", 267 | "mimetype": "text/x-qsharp", 268 | "name": "qsharp", 269 | "version": "0.12" 270 | } 271 | }, 272 | "nbformat": 4, 273 | "nbformat_minor": 4 274 | } 275 | -------------------------------------------------------------------------------- /tests/OpenQasmExporter.Tests/OpenQasmExporter.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | QSharpCommunity.Simulators.OpenQasmExporter.Exporter 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | Test\Bv3.qs 27 | 28 | 29 | Test\CNot.qs 30 | 31 | 32 | Test\FiveQubit1.qs 33 | 34 | 35 | Test\Gates.qs 36 | 37 | 38 | Test\Hadamard.qs 39 | 40 | 41 | Test\Hid3.qs 42 | 43 | 44 | Test\Marg5.qs 45 | 46 | 47 | Test\Toff6.qs 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /tests/OpenQasmExporter.Tests/Test.qs: -------------------------------------------------------------------------------- 1 | namespace Tests { 2 | open Microsoft.Quantum.Intrinsic; 3 | open Microsoft.Quantum.Diagnostics; 4 | open Microsoft.Quantum.Measurement; 5 | 6 | @EntryPoint() 7 | @Test("QSharpCommunity.Simulators.OpenQasmExporter.Exporter") 8 | operation SampleTest() : Unit { 9 | use q = Qubit(); 10 | H(q); 11 | let result = MResetZ(q); 12 | Message($"Result of Hadamard: {result}"); 13 | 14 | // TODO: See if we can actually use test methods; Example below from qRAM project 15 | // let expectedValue = ConstantArray(2^addressSize, [false]); 16 | // let data = EmptyQRAM(addressSize); 17 | // let result = CreateQueryMeasureAllQRAM(data); 18 | // let pairs = Zip(result, expectedValue); 19 | // Ignore(Mapped( 20 | // AllEqualityFactB(_, _, $"Expecting memory contents {expectedValue}, got {result}."), 21 | // pairs 22 | //)); 23 | } 24 | } -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/End2EndTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Text.RegularExpressions; 7 | using Xunit; 8 | 9 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 10 | { 11 | public class End2EndTest 12 | { 13 | const string SOURCE_NAMESPACE = "Microsoft.Quantum.Samples.OpenQasmReader.Tests.Test"; 14 | const string TARGET_NAMESPACE = "Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate"; 15 | 16 | [Fact] 17 | public void HadamardConversionTest() => TestConversion("Hadamard.qs", $"{SOURCE_NAMESPACE}.Hadamard.qasm", $"{TARGET_NAMESPACE}.Hadamard.qs"); 18 | 19 | [Fact] 20 | public void CNotConversionTest() => TestConversion("CNot.qs", $"{SOURCE_NAMESPACE}.CNot.qasm", $"{TARGET_NAMESPACE}.CNot.qs"); 21 | 22 | [Fact] 23 | public void GatesConversionTest() => TestConversion("Gates.qs", $"{SOURCE_NAMESPACE}.Gates.qasm", $"{TARGET_NAMESPACE}.Gates.qs"); 24 | 25 | [Fact] 26 | public void FiveQubitEncodingConversionTest() => TestConversion("FiveQubit1.qs", $"{SOURCE_NAMESPACE}.5qubit1.qasm", $"{TARGET_NAMESPACE}.FiveQubit1.qs"); 27 | 28 | [Fact] 29 | public void BernsteinVaziraniConversionTest() => TestConversion("bv3.qs", $"{SOURCE_NAMESPACE}.bv3.qasm", $"{TARGET_NAMESPACE}.Bv3.qs"); 30 | [Fact] 31 | public void HiddenShiftConversionTest() => TestConversion("hid3.qs", $"{SOURCE_NAMESPACE}.hid3.qasm", $"{TARGET_NAMESPACE}.Hid3.qs"); 32 | [Fact] 33 | public void MargolusConversionTest() => TestConversion("marg5.qs", $"{SOURCE_NAMESPACE}.marg5.qasm", $"{TARGET_NAMESPACE}.Marg5.qs"); 34 | [Fact] 35 | public void ToffoliConversionTest() => TestConversion("toff6.qs", $"{SOURCE_NAMESPACE}.toff6.qasm", $"{TARGET_NAMESPACE}.Toff6.qs"); 36 | 37 | private const string CommonOpenQasmIncludeFile = "qelib1.inc"; 38 | 39 | private static void TestConversion(string name, string inputResourceName, string expectedResourceName) 40 | { 41 | var input = ReadResource(inputResourceName); 42 | var expected = ReadResource(expectedResourceName); ; 43 | 44 | var inputFile = Path.Combine(Path.GetTempPath(), name); 45 | var dummyInclude = Path.Combine(Path.GetTempPath(), CommonOpenQasmIncludeFile); 46 | try 47 | { 48 | //Write OpenQasm program 49 | File.WriteAllText(inputFile, input); 50 | File.WriteAllText(dummyInclude, "gate cx a,b { CX a,b; }"); 51 | 52 | //Transform 53 | var result = Parser.ConvertQasmFile(TARGET_NAMESPACE, inputFile); 54 | 55 | //Reformat result, so they can be compared (unix/windows, layout differences, and copyright headers); 56 | expected = Regex.Replace(expected, @"\s+", " ").Trim().Trim(new char[] { '\uFEFF', '\u200B' }); 57 | result = COPYRIGHTHEADER.Replace("\n", Environment.NewLine) + result; 58 | result = Regex.Replace(result, @"\s+", " ").Trim().Trim(new char[] { '\uFEFF', '\u200B' }); ; 59 | 60 | Assert.Equal(expected, result); 61 | } 62 | finally 63 | { 64 | if (File.Exists(inputFile)) 65 | { 66 | File.Delete(inputFile); 67 | } 68 | if (File.Exists(dummyInclude)) 69 | { 70 | File.Delete(dummyInclude); 71 | } 72 | } 73 | } 74 | 75 | private static string ReadResource(string resourceName) 76 | { 77 | var assembly = Assembly.GetExecutingAssembly(); 78 | using (var stream = assembly.GetManifestResourceStream(resourceName)) 79 | { 80 | if (stream == null) 81 | { 82 | throw new Exception($"Resource {resourceName} not found in {assembly.FullName}. Valid resources are: {String.Join(", ", assembly.GetManifestResourceNames())}."); 83 | } 84 | using (var reader = new StreamReader(stream)) 85 | { 86 | return reader.ReadToEnd(); 87 | } 88 | } 89 | } 90 | 91 | private const string COPYRIGHTHEADER = "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n"; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/FirstLetterToUpperCaseTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using Xunit; 4 | 5 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 6 | { 7 | public class FirstLetterToUpperCaseTest 8 | { 9 | [Fact] 10 | public void UpperCaseResultsUpperCase() 11 | { 12 | Assert.Equal("Abc", Parser.FirstLetterToUpperCase("Abc")); 13 | } 14 | 15 | [Fact] 16 | public void LowerResultsUpperCase() 17 | { 18 | Assert.Equal("Abc", Parser.FirstLetterToUpperCase("abc")); 19 | } 20 | 21 | [Fact] 22 | public void NumberResultsNumber() 23 | { 24 | Assert.Equal("1bc", Parser.FirstLetterToUpperCase("1bc")); 25 | } 26 | 27 | [Fact] 28 | public void SymbolResultsSymbol() 29 | { 30 | Assert.Equal(";bc", Parser.FirstLetterToUpperCase(";bc")); 31 | } 32 | 33 | [Fact] 34 | public void EmptyResultsEmpty() 35 | { 36 | Assert.Equal(string.Empty, Parser.FirstLetterToUpperCase(string.Empty)); 37 | } 38 | 39 | [Fact] 40 | public void NullResultsEmpty() 41 | { 42 | Assert.Equal(string.Empty, Parser.FirstLetterToUpperCase(null)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/IndexedCallTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using Xunit; 4 | 5 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 6 | { 7 | public class IndexedCallTest 8 | { 9 | [Fact] 10 | public void IndexedCallLoopWhenRequiredWithoutIndex() 11 | { 12 | Assert.Equal("q[_idx]", Parser.IndexedCall("q", true)); 13 | } 14 | 15 | [Fact] 16 | public void IndexedCallLoopWhenRequiredWithIndex() 17 | { 18 | Assert.Equal("q[3]", Parser.IndexedCall("q[3]", true)); 19 | } 20 | 21 | [Fact] 22 | public void IndexedCallLoopWhenNotRequiredWithoutIndex() 23 | { 24 | Assert.Equal("q", Parser.IndexedCall("q", false)); 25 | } 26 | 27 | [Fact] 28 | public void IndexedCallLoopWhenMotRequiredWithIndex() 29 | { 30 | Assert.Equal("q[3]", Parser.IndexedCall("q[3]", false)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/OpenQasmReader.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | Microsoft.Quantum.Samples.OpenQasmReader.Tests 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | all 35 | runtime; build; native; contentfiles; analyzers 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseApplicationTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using Xunit; 7 | 8 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 9 | { 10 | public class ParseApplicationTest 11 | { 12 | [Fact] 13 | public void ParseHeaderTest() 14 | { 15 | var input = "OPENQASM 2.0;"; 16 | using (var stream = new StringReader(input)) 17 | { 18 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 19 | 20 | var cRegs = new Dictionary(); 21 | var qRegs = new Dictionary(); 22 | var inside = new StringBuilder(); 23 | var outside = new StringBuilder(); 24 | var conventionalMeasured = new List(); 25 | var qubitMeasured = new List(); 26 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 27 | 28 | //Expecting to end on the ';', so next loop can pick the next token 29 | Assert.Equal(";", enumerator.Current); 30 | } 31 | } 32 | 33 | [Fact] 34 | public void ParseQRegTest() 35 | { 36 | var input = "qreg q[3];"; 37 | using (var stream = new StringReader(input)) 38 | { 39 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 40 | 41 | var cRegs = new Dictionary(); 42 | var qRegs = new Dictionary(); 43 | var inside = new StringBuilder(); 44 | var outside = new StringBuilder(); 45 | var conventionalMeasured = new List(); 46 | var qubitMeasured = new List(); 47 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 48 | 49 | //Expecting to end on the ';', so next loop can pick the next token 50 | Assert.Equal(";", enumerator.Current); 51 | //No traditional registers 52 | Assert.Equal(new string[0], cRegs.Keys); 53 | Assert.Equal(new int[0], cRegs.Values); 54 | //we now have quantum Registers 55 | Assert.Equal(new string[] { "q" }, qRegs.Keys); 56 | Assert.Equal(new int[] { 3 }, qRegs.Values); 57 | //No output 58 | Assert.Equal(string.Empty, inside.ToString()); 59 | Assert.Equal(string.Empty, outside.ToString()); 60 | } 61 | } 62 | 63 | [Fact] 64 | public void ParseCRegTest() 65 | { 66 | var input = "creg c[3];"; 67 | using (var stream = new StringReader(input)) 68 | { 69 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 70 | 71 | var cRegs = new Dictionary(); 72 | var qRegs = new Dictionary(); 73 | var inside = new StringBuilder(); 74 | var outside = new StringBuilder(); 75 | var conventionalMeasured = new List(); 76 | var qubitMeasured = new List(); 77 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 78 | 79 | //Expecting to end on the ';', so next loop can pick the next token 80 | Assert.Equal(";", enumerator.Current); 81 | //we now have traditional cRegisters 82 | Assert.Equal(new string[] { "c" }, cRegs.Keys); 83 | Assert.Equal(new int[] { 3 }, cRegs.Values); 84 | //No quantum registers 85 | Assert.Equal(new string[0], qRegs.Keys); 86 | Assert.Equal(new int[0], qRegs.Values); 87 | //No output 88 | Assert.Equal(string.Empty, inside.ToString()); 89 | Assert.Equal(string.Empty, outside.ToString()); 90 | } 91 | } 92 | 93 | [Fact] 94 | public void ParseGateDefinitionTest() 95 | { 96 | var input = "gate mygate q { H q;}"; 97 | 98 | using (var stream = new StringReader(input)) 99 | { 100 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 101 | 102 | var cRegs = new Dictionary(); 103 | var qRegs = new Dictionary(); 104 | var inside = new StringBuilder(); 105 | var outside = new StringBuilder(); 106 | var conventionalMeasured = new List(); 107 | var qubitMeasured = new List(); 108 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 109 | 110 | //Expecting to end on the '}', so next loop can pick the next token 111 | Assert.Equal("}", enumerator.Current); 112 | //no traditional cRegisters 113 | Assert.Equal(new string[0], cRegs.Keys); 114 | Assert.Equal(new int[0], cRegs.Values); 115 | //No quantum registers 116 | Assert.Equal(new string[0], qRegs.Keys); 117 | Assert.Equal(new int[0], qRegs.Values); 118 | //No output within the method 119 | Assert.Equal(string.Empty, inside.ToString()); 120 | 121 | //Expected operation 122 | Assert.Equal("operation Mygate (q : Qubit) : Unit{H(q);}", 123 | outside.ToString().Trim() 124 | .Replace("\n", string.Empty) 125 | .Replace("\r", string.Empty) 126 | .Replace(" ", string.Empty)); 127 | } 128 | } 129 | 130 | [Fact] 131 | public void ParseIfDefinitionTest() 132 | { 133 | var input = "if (c0 == 1) z q[2];"; 134 | 135 | using (var stream = new StringReader(input)) 136 | { 137 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 138 | 139 | var cRegs = new Dictionary(); 140 | var qRegs = new Dictionary(); 141 | var inside = new StringBuilder(); 142 | var outside = new StringBuilder(); 143 | var conventionalMeasured = new List(); 144 | var qubitMeasured = new List(); 145 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 146 | 147 | //Expecting to end on the ';', so next loop can pick the next token 148 | Assert.Equal(";", enumerator.Current); 149 | //no traditional cRegisters 150 | Assert.Equal(new string[0], cRegs.Keys); 151 | Assert.Equal(new int[0], cRegs.Values); 152 | //No quantum registers 153 | Assert.Equal(new string[0], qRegs.Keys); 154 | Assert.Equal(new int[0], qRegs.Values); 155 | //expected internals 156 | Assert.Equal("if(c0==1){Z(q[2]);}", inside.ToString().Trim() 157 | .Replace("\n", string.Empty) 158 | .Replace("\r", string.Empty) 159 | .Replace(" ", string.Empty)); 160 | 161 | //No outside generation 162 | Assert.Equal(string.Empty, outside.ToString()); 163 | } 164 | } 165 | 166 | [Fact] 167 | public void ParseMeasureDefinitionTest() 168 | { 169 | var input = "measure q[0] -> c0[0];"; 170 | 171 | using (var stream = new StringReader(input)) 172 | { 173 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 174 | 175 | var cRegs = new Dictionary(); 176 | var qRegs = new Dictionary(); 177 | var inside = new StringBuilder(); 178 | var outside = new StringBuilder(); 179 | var conventionalMeasured = new List(); 180 | var qubitMeasured = new List(); 181 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 182 | 183 | //Expecting to end on the ';', so next loop can pick the next token 184 | Assert.Equal(";", enumerator.Current); 185 | //no traditional cRegisters 186 | Assert.Equal(new string[0], cRegs.Keys); 187 | Assert.Equal(new int[0], cRegs.Values); 188 | //No quantum registers 189 | Assert.Equal(new string[0], qRegs.Keys); 190 | Assert.Equal(new int[0], qRegs.Values); 191 | 192 | //q[0] has now been measured, so c0[0] has output 193 | Assert.Equal(new string[] { "c0[0]" }, conventionalMeasured); 194 | 195 | //expected internals 196 | Assert.Equal("set c0 w/= 0 <- M(q[0]);", inside.ToString().Trim() 197 | .Replace("\n", string.Empty) 198 | .Replace("\r", string.Empty) 199 | .Replace(" ", string.Empty)); 200 | 201 | //No outside generation 202 | Assert.Equal(string.Empty, outside.ToString()); 203 | } 204 | } 205 | 206 | [Fact] 207 | public void ParseMeasureMultipleDefinitionTest() 208 | { 209 | var input = "measure q[0] -> c0[0];measure q[1] -> c0[1];measure q[2] -> c0[2];"; 210 | 211 | using (var stream = new StringReader(input)) 212 | { 213 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 214 | 215 | var cRegs = new Dictionary(); 216 | var qRegs = new Dictionary(); 217 | var inside = new StringBuilder(); 218 | var outside = new StringBuilder(); 219 | var conventionalMeasured = new List(); 220 | var qubitMeasured = new List(); 221 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 222 | 223 | //Expecting to end on the ';', so next loop can pick the next token 224 | Assert.Equal(";", enumerator.Current); 225 | //no traditional cRegisters 226 | Assert.Equal(new string[0], cRegs.Keys); 227 | Assert.Equal(new int[0], cRegs.Values); 228 | //No quantum registers 229 | Assert.Equal(new string[0], qRegs.Keys); 230 | Assert.Equal(new int[0], qRegs.Values); 231 | 232 | //q[0] has now been measured, so c0[0] has output 233 | Assert.Equal(new string[] { "c0[0]", "c0[1]", "c0[2]" }, conventionalMeasured); 234 | 235 | //expected internals 236 | Assert.Equal("set c0 w/= 0 <- M(q[0]);set c0 w/= 1 <- M(q[1]);set c0 w/= 2 <- M(q[2]);", inside.ToString().Trim() 237 | .Replace("\n", string.Empty) 238 | .Replace("\r", string.Empty) 239 | .Replace(" ", string.Empty)); 240 | 241 | //No outside generation 242 | Assert.Equal(string.Empty, outside.ToString()); 243 | } 244 | } 245 | 246 | [Fact] 247 | public void ParseMeasureImplicitQubitDefinitionTest() 248 | { 249 | var input = "measure q[0]; H q[1];"; 250 | 251 | using (var stream = new StringReader(input)) 252 | { 253 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 254 | 255 | var cRegs = new Dictionary(); 256 | var qRegs = new Dictionary(); 257 | var inside = new StringBuilder(); 258 | var outside = new StringBuilder(); 259 | var conventionalMeasured = new List(); 260 | var qubitMeasured = new List(); 261 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 262 | 263 | //Expecting to end on the ';', so next loop can pick the next token 264 | Assert.Equal(";", enumerator.Current); 265 | //no traditional cRegisters 266 | Assert.Equal(new string[0], cRegs.Keys); 267 | Assert.Equal(new int[0], cRegs.Values); 268 | //No quantum registers 269 | Assert.Equal(new string[0], qRegs.Keys); 270 | Assert.Equal(new int[0], qRegs.Values); 271 | 272 | //No conventional Registers 273 | Assert.Equal(new string[] { }, conventionalMeasured); 274 | //q[0] has now been implicitly measured 275 | Assert.Equal(new string[] { "q[0]" }, qubitMeasured); 276 | 277 | //expected internals 278 | Assert.Equal("set _out w/= 0 <- M(q[0]);H(q[1]);", inside.ToString().Trim() 279 | .Replace("\n", string.Empty) 280 | .Replace("\r", string.Empty) 281 | .Replace(" ", string.Empty)); 282 | 283 | //No outside generation 284 | Assert.Equal(string.Empty, outside.ToString()); 285 | } 286 | } 287 | 288 | [Fact] 289 | public void ParseMeasureImplicitQubitExpansionDefinitionTest() 290 | { 291 | var input = "measure q; H p[1];"; 292 | 293 | using (var stream = new StringReader(input)) 294 | { 295 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 296 | 297 | var cRegs = new Dictionary(); 298 | var qRegs = new Dictionary() { { "q", 2 } }; 299 | var inside = new StringBuilder(); 300 | var outside = new StringBuilder(); 301 | var conventionalMeasured = new List(); 302 | var qubitMeasured = new List(); 303 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 304 | 305 | //Expecting to end on the ';', so next loop can pick the next token 306 | Assert.Equal(";", enumerator.Current); 307 | //no traditional cRegisters 308 | Assert.Equal(new string[0], cRegs.Keys); 309 | Assert.Equal(new int[0], cRegs.Values); 310 | //One quantum register 311 | Assert.Equal(new string[] { "q" }, qRegs.Keys); 312 | Assert.Equal(new int[] { 2 }, qRegs.Values); 313 | 314 | //No conventional Registers 315 | Assert.Equal(new string[] { }, conventionalMeasured); 316 | //q[0] has now been implicitly measured 317 | Assert.Equal(new string[] { "q[0]", "q[1]" }, qubitMeasured); 318 | 319 | //expected internals 320 | Assert.Equal("set _out w/= 0 <- M(q[0]);set _out w/= 1 <- M(q[1]);H(p[1]);", inside.ToString().Trim() 321 | .Replace("\n", string.Empty) 322 | .Replace("\r", string.Empty) 323 | .Replace(" ", string.Empty)); 324 | 325 | //No outside generation 326 | Assert.Equal(string.Empty, outside.ToString()); 327 | } 328 | } 329 | 330 | [Fact] 331 | public void ParseMidBarrierTest() 332 | { 333 | var input = "qreg q[1];y q;barrier q;z q;"; 334 | 335 | using (var stream = new StringReader(input)) 336 | { 337 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 338 | 339 | var cRegs = new Dictionary(); 340 | var qRegs = new Dictionary(); 341 | var inside = new StringBuilder(); 342 | var outside = new StringBuilder(); 343 | var conventionalMeasured = new List(); 344 | var qubitMeasured = new List(); 345 | Parser.ParseApplication(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 346 | 347 | //Expecting to end on the ';', so next loop can pick the next token 348 | Assert.Equal(";", enumerator.Current); 349 | //no traditional cRegisters 350 | Assert.Equal(new string[0], cRegs.Keys); 351 | Assert.Equal(new int[0], cRegs.Values); 352 | //One quantum register 353 | Assert.Equal(new string[] { "q" }, qRegs.Keys); 354 | Assert.Equal(new int[] { 1 }, qRegs.Values); 355 | 356 | //No measurements 357 | Assert.Equal(new string[] { }, conventionalMeasured); 358 | Assert.Equal(new string[] {}, qubitMeasured); 359 | 360 | //expected internals 361 | Assert.Equal("ApplyToEach(Y, q);ApplyToEach(Z, q);", inside.ToString().Trim() 362 | .Replace("\n", string.Empty) 363 | .Replace("\r", string.Empty) 364 | .Replace(" ", string.Empty)); 365 | 366 | //No outside generation 367 | Assert.Equal(string.Empty, outside.ToString()); 368 | } 369 | } 370 | 371 | } 372 | } -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseBarrierTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using Xunit; 7 | 8 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 9 | { 10 | public class ParseBarrierTest 11 | { 12 | 13 | [Fact] 14 | public void ParseBarrierSingleQubitTest() 15 | { 16 | var input = "barrier q[0];"; 17 | string result = null; 18 | var qRegs = new Dictionary(); 19 | result = ParseBarrier(input, qRegs); 20 | Assert.Equal(";", result); 21 | } 22 | 23 | [Fact] 24 | public void ParseBarrierTwoQubitTest() 25 | { 26 | var input = "barrier q[0],q[1];"; 27 | string result = null; 28 | var qRegs = new Dictionary(); 29 | result = ParseBarrier(input, qRegs); 30 | Assert.Equal(";", result); 31 | } 32 | 33 | [Fact] 34 | public void ParseBarrierMultipleQubitTest() 35 | { 36 | var input = "barrier q[0],q[1],q[2],q[3],q[4],q[5],q[6];"; 37 | string result = null; 38 | var qRegs = new Dictionary(); 39 | result = ParseBarrier(input, qRegs); 40 | Assert.Equal(";", result); 41 | } 42 | 43 | [Fact] 44 | //Parser issue of #58 where barrier parsed to much 45 | public void ParseBarrierMultipleQubitOpenTest() 46 | { 47 | var input = "barrier q[0],q[1],q[2],q[3],q[4],q[5],q[6];othergate"; 48 | string result = null; 49 | var qRegs = new Dictionary(); 50 | result = ParseBarrier(input, qRegs); 51 | Assert.Equal(";", result); 52 | } 53 | 54 | [Fact] 55 | public void ParseBarrierRegisterTest() 56 | { 57 | var input = "barrier q;"; 58 | string result = null; 59 | var qRegs = new Dictionary(); 60 | result = ParseBarrier(input, qRegs); 61 | Assert.Equal(";", result); 62 | } 63 | 64 | /// 65 | /// Helper function top execute ParseBarrier Method 66 | /// 67 | /// Test file 68 | /// resultstring 69 | private static string ParseBarrier(string input, Dictionary qRegs) 70 | { 71 | using (var stream = new StringReader(input)) 72 | { 73 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 74 | enumerator.MoveNext(); 75 | Parser.ParseBarrier(enumerator, qRegs); 76 | return enumerator.Current; 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseCalculationTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System.IO; 4 | using Xunit; 5 | 6 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 7 | { 8 | public class ParseCalculationTest 9 | { 10 | readonly string[] TestEndMarker = new string[] { ";" }; 11 | 12 | [Fact] 13 | public void ParseCalculationNumberResultsIsDecimal() 14 | { 15 | var input = "1;"; 16 | string result = null; 17 | result = ParseCalculation(input, TestEndMarker); 18 | Assert.Equal("1.0", result); 19 | } 20 | 21 | [Fact] 22 | public void ParseCalculationPiResultsIsMethod() 23 | { 24 | var input = "pi;"; 25 | string result = null; 26 | result = ParseCalculation(input, TestEndMarker); 27 | Assert.Equal("PI()", result); 28 | } 29 | 30 | [Fact] 31 | public void ParseCalculationAddResultsIsAddFormula() 32 | { 33 | var input = "1+3;"; 34 | string result = null; 35 | result = ParseCalculation(input, TestEndMarker); 36 | Assert.Equal("1.0+3.0", result); 37 | } 38 | 39 | [Fact] 40 | public void ParseCalculationLargeMinusResultsIsMinusFormula() 41 | { 42 | var input = "12345678-90;"; 43 | string result = null; 44 | result = ParseCalculation(input, TestEndMarker); 45 | Assert.Equal("12345678.0-90.0", result); 46 | } 47 | 48 | [Fact] 49 | public void ParseCalculationPiDivideResultsIsPiDivide() 50 | { 51 | var input = "pi/2;"; 52 | string result = null; 53 | result = ParseCalculation(input, TestEndMarker); 54 | Assert.Equal("PI()/2.0", result); 55 | } 56 | 57 | [Fact] 58 | public void ParseCalculationParenthesesResultsParentheses() 59 | { 60 | var input = "14+(3/1)*13;"; 61 | string result = null; 62 | result = ParseCalculation(input, TestEndMarker); 63 | Assert.Equal("14.0+(3.0/1.0)*13.0", result); 64 | } 65 | 66 | [Fact] 67 | public void ParseCalculationFirstEndMarkerResultsRestIgnore() 68 | { 69 | var input = "19;13)"; 70 | string result = null; 71 | result = ParseCalculation(input, new string[]{ ";", ")"}); 72 | Assert.Equal("19.0", result); 73 | } 74 | 75 | [Fact] 76 | public void ParseCalculationSecondEndMarkerResultsRestIgnore() 77 | { 78 | var input = "19)13;"; 79 | string result = null; 80 | result = ParseCalculation(input, new string[] { ";", ")" }); 81 | Assert.Equal("19.0", result); 82 | } 83 | 84 | [Fact] 85 | public void ParseCalculationNoEndMarkerResultsNotIgnore() 86 | { 87 | var input = "19-13;"; 88 | string result = null; 89 | result = ParseCalculation(input, new string[] { ";", ")" }); 90 | Assert.Equal("19.0-13.0", result); 91 | } 92 | 93 | [Fact] 94 | public void ParseCalculationReferencesResultsReferences() 95 | { 96 | var input = "q_1+5/14-q[12];"; 97 | string result = null; 98 | result = ParseCalculation(input, TestEndMarker); 99 | Assert.Equal("q_1+5.0/14.0-q[12]", result); 100 | } 101 | 102 | [Fact] 103 | public void ParseCalculationScientificResultsScientific() 104 | { 105 | var input = "5.85167231706864e-9;"; 106 | string result = null; 107 | result = ParseCalculation(input, TestEndMarker); 108 | Assert.Equal("5.85167231706864e-9", result); 109 | } 110 | 111 | /// 112 | /// Helper function top execute ParseCalculation Method 113 | /// 114 | /// Test file 115 | /// Markers to stop on 116 | /// resultstring 117 | private static string ParseCalculation(string input, params string[] endmarkers) 118 | { 119 | string result; 120 | using (var stream = new StringReader(input)) 121 | { 122 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 123 | enumerator.MoveNext(); 124 | result = Parser.ParseCalculation(enumerator, endmarkers); 125 | } 126 | 127 | return result; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseConditionTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using Xunit; 9 | 10 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 11 | { 12 | public class ParseConditionTest 13 | { 14 | readonly string[] TestEndMarker = new string[] { ")" }; 15 | 16 | [Fact] 17 | public void ParseConditionNumberTestResultsIsNumberTest() 18 | { 19 | var input = "1==1)"; 20 | string result = null; 21 | var cRegs = new Dictionary(); 22 | result = ParseCondition(input, cRegs, TestEndMarker); 23 | Assert.Equal("1==1", result); 24 | } 25 | 26 | [Fact] 27 | public void ParseConditionCregNumberTestResultsNumberConversionTest() 28 | { 29 | var input = "1==a)"; 30 | string result = null; 31 | var cRegs = new Dictionary() { { "a", 1 } }; 32 | result = ParseCondition(input, cRegs, TestEndMarker); 33 | Assert.Equal("1==ResultAsInt(a)", result); 34 | } 35 | 36 | [Fact] 37 | public void ParseConditionCregPiTestResultsPiConversionTest() 38 | { 39 | var input = "pi() { { "q_1", 1 } }; 42 | result = ParseCondition(input, cRegs, TestEndMarker); 43 | Assert.Equal("PI()() { { "q_1", 1 } }; 52 | result = ParseCondition(input, cRegs, TestEndMarker); 53 | Assert.Equal("(3+6)==9", result); 54 | } 55 | 56 | [Fact] 57 | public void ParseConditionDeepNestedTestResultsDeepNestedTest() 58 | { 59 | var input = "(3+(6-2))!=9)"; 60 | string result = null; 61 | var cRegs = new Dictionary() { { "q_1", 1 } }; 62 | result = ParseCondition(input, cRegs, TestEndMarker); 63 | Assert.Equal("(3+(6-2))!=9", result); 64 | } 65 | 66 | 67 | /// 68 | /// Helper function top execute ParseCalculation Method 69 | /// 70 | /// Test file 71 | /// Traditional register 72 | /// Markers to stop on 73 | /// resultstring 74 | private static string ParseCondition(string input, Dictionary cRegs, params string[] endmarkers) 75 | { 76 | string result; 77 | using (var stream = new StringReader(input)) 78 | { 79 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 80 | enumerator.MoveNext(); 81 | result = Parser.ParseCondition(enumerator, cRegs, endmarkers); 82 | } 83 | 84 | return result; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseIncludeTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using Xunit; 9 | 10 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 11 | { 12 | public class ParseIncludeTest 13 | { 14 | [Fact] 15 | public void MissingIncludeResultsMessageInComment() 16 | { 17 | var input = "include \"doesnotexist.inc\";"; 18 | 19 | using (var stream = new StringReader(input)) 20 | { 21 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 22 | enumerator.MoveNext(); //include 23 | 24 | var cRegs = new Dictionary(); 25 | var qRegs = new Dictionary(); 26 | var inside = new StringBuilder(); 27 | var outside = new StringBuilder(); 28 | var conventionalMeasured = new List(); 29 | var qubitMeasured = new List(); 30 | Parser.ParseInclude(enumerator, cRegs, qRegs, "path", inside, outside, conventionalMeasured, qubitMeasured); 31 | 32 | //Expecting to end on the ';', so next loop can pick the next token 33 | Assert.Equal(";", enumerator.Current); 34 | //no traditional cRegisters 35 | Assert.Equal(new string[0], cRegs.Keys); 36 | Assert.Equal(new int[0], cRegs.Values); 37 | //No quantum registers 38 | Assert.Equal(new string[0], qRegs.Keys); 39 | Assert.Equal(new int[0], qRegs.Values); 40 | //No output within the method 41 | Assert.Equal(string.Empty, inside.ToString()); 42 | 43 | var path = Path.Combine("doesnotexist.inc"); 44 | 45 | //Expected operation 46 | Assert.Equal(string.Format("//The file {0} to be included in the QASM was not found. Generated without it.", path), 47 | outside.ToString().Trim() 48 | .Replace("\n", string.Empty) 49 | .Replace("\r", string.Empty) 50 | .Replace(" ", string.Empty)); 51 | } 52 | } 53 | 54 | [Fact] 55 | public void CorrectIncludeResultsInIncludedCode() 56 | { 57 | var fileName = Guid.NewGuid().ToString(); 58 | 59 | try 60 | { 61 | File.WriteAllText(fileName, "qreg q[1];"); 62 | 63 | var input = string.Format("include \"{0}\";", fileName); 64 | 65 | using (var stream = new StringReader(input)) 66 | { 67 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 68 | enumerator.MoveNext(); //include 69 | 70 | var cRegs = new Dictionary(); 71 | var qRegs = new Dictionary(); 72 | var inside = new StringBuilder(); 73 | var outside = new StringBuilder(); 74 | var conventionalMeasured = new List(); 75 | var qubitMeasured = new List(); 76 | Parser.ParseInclude(enumerator, cRegs, qRegs, ".", inside, outside, conventionalMeasured, qubitMeasured); 77 | 78 | //Expecting to end on the ';', so next loop can pick the next token 79 | Assert.Equal(";", enumerator.Current); 80 | //no traditional cRegisters 81 | Assert.Equal(new string[0], cRegs.Keys); 82 | Assert.Equal(new int[0], cRegs.Values); 83 | //we now have quantum Registers 84 | Assert.Equal(new string[] { "q" }, qRegs.Keys); 85 | Assert.Equal(new int[] { 1 }, qRegs.Values); 86 | //No output within the method or outside 87 | Assert.Equal(string.Empty, inside.ToString()); 88 | Assert.Equal(string.Empty, outside.ToString()); 89 | } 90 | } 91 | finally 92 | { 93 | File.Delete(fileName); 94 | } 95 | } 96 | 97 | [Fact] 98 | public void IncludeEmptyFileResultsInIgnoredCode() 99 | { 100 | var fileName = Guid.NewGuid().ToString(); 101 | 102 | try 103 | { 104 | File.WriteAllText(fileName, string.Empty); 105 | 106 | var input = string.Format("include \"{0}\";", fileName); 107 | 108 | using (var stream = new StringReader(input)) 109 | { 110 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 111 | enumerator.MoveNext(); //include 112 | 113 | var cRegs = new Dictionary(); 114 | var qRegs = new Dictionary(); 115 | var inside = new StringBuilder(); 116 | var outside = new StringBuilder(); 117 | var conventionalMeasured = new List(); 118 | var qubitMeasured = new List(); 119 | Parser.ParseInclude(enumerator, cRegs, qRegs, ".", inside, outside, conventionalMeasured, qubitMeasured); 120 | 121 | //Expecting to end on the ';', so next loop can pick the next token 122 | Assert.Equal(";", enumerator.Current); 123 | //no traditional cRegisters 124 | Assert.Equal(new string[0], cRegs.Keys); 125 | Assert.Equal(new int[0], cRegs.Values); 126 | //no quantum Registers 127 | Assert.Equal(new string[0], cRegs.Keys); 128 | Assert.Equal(new int[0], cRegs.Values); 129 | //No output within the method or outside 130 | Assert.Equal(string.Empty, inside.ToString()); 131 | Assert.Equal(string.Empty, outside.ToString()); 132 | } 133 | } 134 | finally 135 | { 136 | File.Delete(fileName); 137 | } 138 | } 139 | 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/ParseOpenQasmHeaderTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System.IO; 4 | using Xunit; 5 | 6 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 7 | { 8 | public class ParseOpenQasmHeaderTest 9 | { 10 | [Fact] 11 | public void HeaderWithPointCommaResultsNoCrash() 12 | { 13 | var input = "2.0;"; 14 | using (var stream = new StringReader(input)) 15 | { 16 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 17 | Parser.ParseOpenQasmHeader(enumerator); 18 | 19 | //Expecting to end on the ';', so next loop can pick the next token 20 | Assert.Equal(";", enumerator.Current); 21 | } 22 | } 23 | 24 | [Fact] 25 | public void HeaderWithWrongVersionNoCrash() 26 | { 27 | var input = "3.0;"; 28 | using (var stream = new StringReader(input)) 29 | { 30 | var enumerator = Parser.Tokenizer(stream).GetEnumerator(); 31 | Parser.ParseOpenQasmHeader(enumerator); 32 | 33 | //Expecting to end on the ';', so next loop can pick the next token 34 | Assert.Equal(";", enumerator.Current); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/5qubit1.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // OpenQASM 2.0 sample file 5 | // Generated as QASM 1.0 from LIQUi|> on 8/15/16, manually converted to OpenQASM 2.0 on 9/13/18 6 | // Description: 5 qubit code encoder for logical |1> input state 7 | 8 | OPENQASM 2.0; 9 | 10 | include "qelib1.inc"; 11 | 12 | qreg q[5]; 13 | creg c[3]; 14 | 15 | x q[4]; 16 | h q[3]; 17 | cx q[4], q[2]; 18 | cx q[1], q[2]; 19 | h q[4]; 20 | h q[2]; 21 | h q[1]; 22 | cx q[1], q[2]; 23 | h q[2]; 24 | h q[1]; 25 | cx q[1], q[2]; 26 | cx q[4], q[2]; 27 | cx q[4], q[2]; 28 | h q[2]; 29 | h q[4]; 30 | cx q[4], q[2]; 31 | h q[2]; 32 | h q[4]; 33 | cx q[4], q[2]; 34 | cx q[3], q[2]; 35 | cx q[1], q[2]; 36 | h q[2]; 37 | h q[1]; 38 | cx q[1], q[2]; 39 | h q[2]; 40 | h q[1]; 41 | cx q[1], q[2]; 42 | cx q[1], q[2]; 43 | cx q[0], q[2]; 44 | h q[1]; 45 | h q[2]; 46 | h q[0]; 47 | cx q[0], q[2]; 48 | h q[2]; 49 | h q[0]; 50 | cx q[0], q[2]; 51 | cx q[3], q[2]; 52 | measure q[0]; 53 | cx q[4], q[2]; 54 | h q[3]; 55 | h q[2]; 56 | h q[4]; 57 | cx q[4], q[2]; 58 | h q[2]; 59 | h q[4]; 60 | cx q[4], q[2]; 61 | cx q[3], q[2]; 62 | cx q[4], q[2]; 63 | measure q[3]; 64 | h q[2]; 65 | h q[4]; 66 | cx q[4], q[2]; 67 | h q[2]; 68 | h q[4]; 69 | cx q[4], q[2]; 70 | cx q[1], q[2]; 71 | measure q[4] -> c[0]; 72 | measure q[1] -> c[1]; 73 | measure q[2] -> c[2]; 74 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/CNot.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[2]; 6 | creg c[2]; 7 | H q[0]; 8 | cx q[0],q[1]; 9 | measure q -> c; -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/Gates.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | gate majority a,b,c 6 | { 7 | cx c,b; 8 | cx c,a; 9 | ccx a,b,c; 10 | } 11 | 12 | qreg q[3]; 13 | majority q[0],q[1],q[2] -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/Hadamard.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[1]; 6 | creg c[1]; 7 | H q[0]; 8 | measure q[0] -> c[0]; -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/bv3.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // OpenQASM 2.0 sample file 5 | // Generated as QASM 1.0 from LIQUi|> on 8/14/16, manually converted to OpenQASM 2.0 on 9/13/18 6 | // Description: Bernstein Vazirani problem for instance = (0,0,1,1) 7 | 8 | OPENQASM 2.0; 9 | 10 | include "qelib1.inc"; 11 | 12 | qreg q[5]; 13 | creg c[4]; 14 | 15 | x q[2]; 16 | h q[0]; 17 | h q[1]; 18 | h q[2]; 19 | h q[3]; 20 | h q[4]; 21 | cx q[0], q[2]; 22 | cx q[1], q[2]; 23 | h q[0]; 24 | h q[1]; 25 | h q[3]; 26 | h q[4]; 27 | measure q[0]; 28 | measure q[1]; 29 | measure q[3]; 30 | measure q[4]; 31 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/hid3.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // OpenQASM 2.0 sample file 5 | // Generated as QASM 1.0 from LIQUi|> on 6/30/16, manually converted to OpenQASM 2.0 on 9/13/18 6 | // Description: Hidden shift problem on inner product bent function for instance = (0,0,1,1) 7 | 8 | OPENQASM 2.0; 9 | 10 | include "qelib1.inc"; 11 | 12 | qreg q[5]; 13 | creg c[4]; 14 | 15 | h q[1]; 16 | h q[2]; 17 | h q[3]; 18 | h q[4]; 19 | x q[1]; 20 | x q[2]; 21 | h q[2]; 22 | cx q[1], q[2]; 23 | h q[2]; 24 | x q[1]; 25 | x q[2]; 26 | cx q[4], q[2]; 27 | h q[2]; 28 | h q[4]; 29 | cx q[4], q[2]; 30 | h q[2]; 31 | h q[4]; 32 | cx q[4], q[2]; 33 | h q[2]; 34 | cx q[3], q[2]; 35 | h q[2]; 36 | h q[1]; 37 | h q[2]; 38 | h q[3]; 39 | h q[4]; 40 | h q[2]; 41 | cx q[3], q[2]; 42 | h q[2]; 43 | cx q[4], q[2]; 44 | h q[2]; 45 | h q[4]; 46 | cx q[4], q[2]; 47 | h q[2]; 48 | h q[4]; 49 | cx q[4], q[2]; 50 | h q[2]; 51 | cx q[1], q[2]; 52 | h q[2]; 53 | h q[1]; 54 | h q[2]; 55 | h q[3]; 56 | h q[4]; 57 | measure q[1] -> c[0]; 58 | measure q[2] -> c[1]; 59 | measure q[3] -> c[2]; 60 | measure q[4] -> c[3]; 61 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/marg5.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // OpenQASM 2.0 sample file 5 | // Generated as QASM 1.0 from LIQUi|> on 6/30/16, manually converted to OpenQASM 2.0 on 9/13/18 6 | // Description: Margolus gate implementation for input state = (0,1,0,1) 7 | 8 | OPENQASM 2.0; 9 | 10 | include "qelib1.inc"; 11 | 12 | qreg q[5]; 13 | creg c[3]; 14 | 15 | x q[2]; 16 | x q[4]; 17 | s q[2]; 18 | h q[2]; 19 | t q[2]; 20 | h q[2]; 21 | sdg q[2]; 22 | cx q[3], q[2]; 23 | s q[2]; 24 | h q[2]; 25 | t q[2]; 26 | h q[2]; 27 | sdg q[2]; 28 | cx q[4], q[2]; 29 | s q[2]; 30 | h q[2]; 31 | tdg q[2]; 32 | h q[2]; 33 | sdg q[2]; 34 | cx q[3], q[2]; 35 | s q[2]; 36 | h q[2]; 37 | tdg q[2]; 38 | h q[2]; 39 | sdg q[2]; 40 | measure q[2] -> c[0]; 41 | measure q[3] -> c[1]; 42 | measure q[4] -> c[2]; 43 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Test/toff6.qasm: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // OpenQASM 2.0 sample file 5 | // Generated as QASM 1.0 from LIQUi|> on 6/30/16, manually converted to OpenQASM 2.0 on 9/13/18// OpenQASM 2.0 sample file 6 | // Description: Toffoli gate implementation for input state = (1,1,0,0) 7 | 8 | OPENQASM 2.0; 9 | 10 | include "qelib1.inc"; 11 | 12 | qreg q[5]; 13 | creg c[3]; 14 | 15 | x q[3]; 16 | x q[4]; 17 | tdg q[2]; 18 | tdg q[3]; 19 | h q[4]; 20 | cx q[4], q[2]; 21 | t q[2]; 22 | cx q[3], q[2]; 23 | tdg q[2]; 24 | cx q[4], q[2]; 25 | h q[2]; 26 | h q[4]; 27 | cx q[4], q[2]; 28 | h q[2]; 29 | h q[4]; 30 | cx q[4], q[2]; 31 | cx q[3], q[2]; 32 | t q[2]; 33 | cx q[3], q[2]; 34 | cx q[4], q[2]; 35 | h q[2]; 36 | h q[4]; 37 | cx q[4], q[2]; 38 | h q[2]; 39 | h q[4]; 40 | t q[2]; 41 | tdg q[4]; 42 | cx q[3], q[2]; 43 | h q[4]; 44 | measure q[2] -> c[0]; 45 | measure q[3] -> c[1]; 46 | measure q[4] -> c[2]; 47 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/TokenizerTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | using System.IO; 4 | using System.Linq; 5 | using Xunit; 6 | 7 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests 8 | { 9 | public class TokenizerTest 10 | { 11 | [Fact] 12 | public void EmptyFileResultsNoTokens() 13 | { 14 | var input = string.Empty; 15 | string[] result = null; 16 | result = Tokenize(input); 17 | Assert.Empty(result); 18 | } 19 | 20 | [Fact] 21 | public void CommentOnlyResultsNoTokens() 22 | { 23 | var input = "//H q1"; 24 | string[] result = null; 25 | result = Tokenize(input); 26 | Assert.Empty(result); 27 | } 28 | 29 | [Fact] 30 | public void WhiteCharactersResultsNoTokens() 31 | { 32 | var input = "\t\n\r\v "; 33 | string[] result = null; 34 | result = Tokenize(input); 35 | Assert.Empty(result); 36 | } 37 | 38 | [Fact] 39 | public void CommentsRecognizeUnixLineEndingResultsTokens() 40 | { 41 | var input = "before\n//H\nafter"; 42 | string[] result = null; 43 | result = Tokenize(input); 44 | Assert.Equal(new string[] { "before", "after" }, result); 45 | } 46 | 47 | [Fact] 48 | public void CommentsRecognizeWindowsLineEndingResultsTokens() 49 | { 50 | var input = "before\r\n//H\r\nafter"; 51 | string[] result = null; 52 | result = Tokenize(input); 53 | Assert.Equal(new string[]{ "before", "after"}, result); 54 | } 55 | 56 | [Fact] 57 | public void NonCommentSpecialCharacterResultsTokens() 58 | { 59 | // Starting with the '/' instead of "//" 60 | var input = "/(){},;+-*=!<>a"; 61 | string[] result = null; 62 | result = Tokenize(input); 63 | Assert.Equal(input.Select(c => "" + c), result); 64 | } 65 | 66 | [Fact] 67 | public void NonCommentReferenceResultsTokens() 68 | { 69 | //Not valid QASM, but extreme case 70 | var input = "6/pi/[11.12+14]/q_1"; 71 | string[] result = null; 72 | result = Tokenize(input); 73 | Assert.Equal(new string[] { 74 | "6", "/", "pi", "/", "[11.12", 75 | "+", "14]", "/", "q_1" } 76 | , result); 77 | } 78 | 79 | [Fact] 80 | public void SimpleFormulaResultsTokens() 81 | { 82 | var input = "1+16-(4/3)*14"; 83 | string[] result = null; 84 | result = Tokenize(input); 85 | Assert.Equal(new string[] { 86 | "1", "+", "16", "-", 87 | "(", "4", "/", "3", 88 | ")", "*", "14" } 89 | , result); 90 | } 91 | 92 | [Fact] 93 | public void SimpleGateCallResultsTokens() 94 | { 95 | var input = "RGate(14.12) q1[3],q_2;"; 96 | string[] result = null; 97 | result = Tokenize(input); 98 | Assert.Equal(new string[] { 99 | "RGate", "(", "14.12", ")", 100 | "q1[3]", ",", "q_2", ";" } 101 | , result); 102 | } 103 | 104 | [Fact] 105 | public void SpecialCharacterResultsTokens() 106 | { 107 | var input = "(){},;+-*=!<>a"; 108 | string[] result = null; 109 | result = Tokenize(input); 110 | Assert.Equal(input.Select(c => "" +c), result); 111 | } 112 | 113 | /// 114 | /// Helper function to test the tokenizer 115 | /// 116 | /// String to use as input 117 | /// Tokens 118 | private static string[] Tokenize(string input) 119 | { 120 | string[] result; 121 | using (var stream = new StringReader(input)) 122 | { 123 | result = Parser.Tokenizer(stream).ToArray(); 124 | } 125 | 126 | return result; 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Bv3.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | open Microsoft.Quantum.Intrinsic; 5 | open Microsoft.Quantum.Canon; 6 | open Microsoft.Quantum.Math; 7 | 8 | operation Bv3 () : Result[] { 9 | 10 | mutable _out = new Result[4]; 11 | mutable c = new Result[4]; 12 | 13 | use q = Qubit[5]; 14 | X(q[2]); 15 | H(q[0]); 16 | H(q[1]); 17 | H(q[2]); 18 | H(q[3]); 19 | H(q[4]); 20 | CNOT(q[0], q[2]); 21 | CNOT(q[1], q[2]); 22 | H(q[0]); 23 | H(q[1]); 24 | H(q[3]); 25 | H(q[4]); 26 | set _out w/= 0 <- M(q[0]); 27 | set _out w/= 1 <- M(q[1]); 28 | set _out w/= 2 <- M(q[3]); 29 | set _out w/= 3 <- M(q[4]); 30 | ResetAll(q); 31 | 32 | return [_out[0], _out[1], _out[2], _out[3]]; 33 | } 34 | 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/CNot.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation CNot () : Result[] { 10 | 11 | mutable c = new Result[2]; 12 | 13 | use q = Qubit[2]; 14 | H(q[0]); 15 | CNOT(q[0], q[1]); 16 | 17 | for _idx in 0 .. Length(c) - 1 { 18 | set c w/= _idx <- M(q[_idx]); 19 | } 20 | 21 | ResetAll(q); 22 | 23 | return [c[0], c[1]]; 24 | } 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/FiveQubit1.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation FiveQubit1 () : Result[] { 10 | 11 | mutable _out = new Result[2]; 12 | mutable c = new Result[3]; 13 | 14 | use q = Qubit[5]; 15 | X(q[4]); 16 | H(q[3]); 17 | CNOT(q[4], q[2]); 18 | CNOT(q[1], q[2]); 19 | H(q[4]); 20 | H(q[2]); 21 | H(q[1]); 22 | CNOT(q[1], q[2]); 23 | H(q[2]); 24 | H(q[1]); 25 | CNOT(q[1], q[2]); 26 | CNOT(q[4], q[2]); 27 | CNOT(q[4], q[2]); 28 | H(q[2]); 29 | H(q[4]); 30 | CNOT(q[4], q[2]); 31 | H(q[2]); 32 | H(q[4]); 33 | CNOT(q[4], q[2]); 34 | CNOT(q[3], q[2]); 35 | CNOT(q[1], q[2]); 36 | H(q[2]); 37 | H(q[1]); 38 | CNOT(q[1], q[2]); 39 | H(q[2]); 40 | H(q[1]); 41 | CNOT(q[1], q[2]); 42 | CNOT(q[1], q[2]); 43 | CNOT(q[0], q[2]); 44 | H(q[1]); 45 | H(q[2]); 46 | H(q[0]); 47 | CNOT(q[0], q[2]); 48 | H(q[2]); 49 | H(q[0]); 50 | CNOT(q[0], q[2]); 51 | CNOT(q[3], q[2]); 52 | set _out w/= 0 <- M(q[0]); 53 | CNOT(q[4], q[2]); 54 | H(q[3]); 55 | H(q[2]); 56 | H(q[4]); 57 | CNOT(q[4], q[2]); 58 | H(q[2]); 59 | H(q[4]); 60 | CNOT(q[4], q[2]); 61 | CNOT(q[3], q[2]); 62 | CNOT(q[4], q[2]); 63 | set _out w/= 1 <- M(q[3]); 64 | H(q[2]); 65 | H(q[4]); 66 | CNOT(q[4], q[2]); 67 | H(q[2]); 68 | H(q[4]); 69 | CNOT(q[4], q[2]); 70 | CNOT(q[1], q[2]); 71 | set c w/= 0 <- M(q[4]); 72 | set c w/= 1 <- M(q[1]); 73 | set c w/= 2 <- M(q[2]); 74 | ResetAll(q); 75 | 76 | return [_out[0], _out[1], c[0], c[1], c[2]]; 77 | } 78 | 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Gates.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | 10 | operation Majority (a : Qubit, b : Qubit, c : Qubit) : Unit { 11 | CNOT(c, b); 12 | CNOT(c, a); 13 | CCNOT(a, b, c); 14 | } 15 | 16 | operation Gates () : Unit { 17 | use q = Qubit[3]; 18 | Majority(q[0], q[1], q[2]); 19 | ResetAll(q); 20 | } 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Hadamard.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation Hadamard () : Result[] { 10 | 11 | mutable c = new Result[1]; 12 | 13 | use q = Qubit[1]; 14 | H(q[0]); 15 | set c w/= 0 <- M(q[0]); 16 | ResetAll(q); 17 | 18 | return [c[0]]; 19 | } 20 | 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Hid3.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation Hid3 () : Result[] { 10 | 11 | mutable c = new Result[4]; 12 | 13 | use q = Qubit[5]; 14 | H(q[1]); 15 | H(q[2]); 16 | H(q[3]); 17 | H(q[4]); 18 | X(q[1]); 19 | X(q[2]); 20 | H(q[2]); 21 | CNOT(q[1], q[2]); 22 | H(q[2]); 23 | X(q[1]); 24 | X(q[2]); 25 | CNOT(q[4], q[2]); 26 | H(q[2]); 27 | H(q[4]); 28 | CNOT(q[4], q[2]); 29 | H(q[2]); 30 | H(q[4]); 31 | CNOT(q[4], q[2]); 32 | H(q[2]); 33 | CNOT(q[3], q[2]); 34 | H(q[2]); 35 | H(q[1]); 36 | H(q[2]); 37 | H(q[3]); 38 | H(q[4]); 39 | H(q[2]); 40 | CNOT(q[3], q[2]); 41 | H(q[2]); 42 | CNOT(q[4], q[2]); 43 | H(q[2]); 44 | H(q[4]); 45 | CNOT(q[4], q[2]); 46 | H(q[2]); 47 | H(q[4]); 48 | CNOT(q[4], q[2]); 49 | H(q[2]); 50 | CNOT(q[1], q[2]); 51 | H(q[2]); 52 | H(q[1]); 53 | H(q[2]); 54 | H(q[3]); 55 | H(q[4]); 56 | set c w/= 0 <- M(q[1]); 57 | set c w/= 1 <- M(q[2]); 58 | set c w/= 2 <- M(q[3]); 59 | set c w/= 3 <- M(q[4]); 60 | ResetAll(q); 61 | 62 | return [c[0], c[1], c[2], c[3]]; 63 | } 64 | 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Marg5.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation Marg5 () : Result[] { 10 | 11 | mutable c = new Result[3]; 12 | 13 | use q = Qubit[5]; 14 | X(q[2]); 15 | X(q[4]); 16 | S(q[2]); 17 | H(q[2]); 18 | T(q[2]); 19 | H(q[2]); 20 | Adjoint S(q[2]); 21 | CNOT(q[3], q[2]); 22 | S(q[2]); 23 | H(q[2]); 24 | T(q[2]); 25 | H(q[2]); 26 | Adjoint S(q[2]); 27 | CNOT(q[4], q[2]); 28 | S(q[2]); 29 | H(q[2]); 30 | Adjoint T(q[2]); 31 | H(q[2]); 32 | Adjoint S(q[2]); 33 | CNOT(q[3], q[2]); 34 | S(q[2]); 35 | H(q[2]); 36 | Adjoint T(q[2]); 37 | H(q[2]); 38 | Adjoint S(q[2]); 39 | set c w/= 0 <- M(q[2]); 40 | set c w/= 1 <- M(q[3]); 41 | set c w/= 2 <- M(q[4]); 42 | ResetAll(q); 43 | 44 | return [c[0], c[1], c[2]]; 45 | } 46 | 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/OpenQasmReader.Tests/Validate/Toff6.qs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | namespace Microsoft.Quantum.Samples.OpenQasmReader.Tests.Validate { 4 | 5 | open Microsoft.Quantum.Intrinsic; 6 | open Microsoft.Quantum.Canon; 7 | open Microsoft.Quantum.Math; 8 | 9 | operation Toff6 () : Result[] { 10 | 11 | mutable c = new Result[3]; 12 | 13 | use q = Qubit[5]; 14 | X(q[3]); 15 | X(q[4]); 16 | Adjoint T(q[2]); 17 | Adjoint T(q[3]); 18 | H(q[4]); 19 | CNOT(q[4], q[2]); 20 | T(q[2]); 21 | CNOT(q[3], q[2]); 22 | Adjoint T(q[2]); 23 | CNOT(q[4], q[2]); 24 | H(q[2]); 25 | H(q[4]); 26 | CNOT(q[4], q[2]); 27 | H(q[2]); 28 | H(q[4]); 29 | CNOT(q[4], q[2]); 30 | CNOT(q[3], q[2]); 31 | T(q[2]); 32 | CNOT(q[3], q[2]); 33 | CNOT(q[4], q[2]); 34 | H(q[2]); 35 | H(q[4]); 36 | CNOT(q[4], q[2]); 37 | H(q[2]); 38 | H(q[4]); 39 | T(q[2]); 40 | Adjoint T(q[4]); 41 | CNOT(q[3], q[2]); 42 | H(q[4]); 43 | set c w/= 0 <- M(q[2]); 44 | set c w/= 1 <- M(q[3]); 45 | set c w/= 2 <- M(q[4]); 46 | ResetAll(q); 47 | 48 | return [c[0], c[1], c[2]]; 49 | } 50 | 51 | } 52 | 53 | 54 | --------------------------------------------------------------------------------