This commit is contained in:
Microsoft Open Source 2019-06-04 13:02:58 -07:00 коммит произвёл Christopher Granade
Родитель 3c3e4257b3
Коммит cda82848d6
114 изменённых файлов: 9329 добавлений и 0 удалений

32
.github/ISSUE_TEMPLATE/bug_report.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System information**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

20
.github/ISSUE_TEMPLATE/feature_request.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

3
.gitignore поставляемый
Просмотреть файл

@ -1,3 +1,5 @@
.ipynb_checkpoints
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
@ -23,6 +25,7 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
drops/
# Visual Studio 2015/2017 cache/options directory
.vs/

5
.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
{
"files.associations": {
"**/build/*.yml": "azure-pipelines"
}
}

55
CONTRIBUTING.md Normal file
Просмотреть файл

@ -0,0 +1,55 @@
# Contributing to IQ#
Welcome, and thank you for your interest in contributing to IQ#!
There are many ways in which you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved.
For more details on how to contribute to IQ# or the rest of the Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/quantum/contributing/).
## Asking Questions
Have a question? The `q#` tags on [Stack Overflow](https://stackoverflow.com/questions/tagged/q%23) and [Quantum Computing StackExchange](https://quantumcomputing.stackexchange.com/questions/tagged/q%23) are great places to ask questions about Q#, Quantum Development Kit and quantum computing in general.
You can learn more about our work on the [Q# Development Blog](https://devblogs.microsoft.com/qsharp/) and ask questions in the comments as well.
However you ask it, your well-worded question will serve as a resource to others searching for help.
## Reporting Issues
Have you identified a reproducible problem in the Quantum Development Kit?
Have a feature request?
We want to hear about it!
Here's how you can make reporting your issue as effective as possible.
### Identify Where to Report
The Quantum Development Kit is distributed across multiple repositories. Try to file the issue against the correct repository.
Check the list [in the contribution guide](https://docs.microsoft.com/quantum/contributing/#where-do-contributions-go) if you aren't sure which repo is correct.
### Writing Good Bug Reports and Feature Requests
File a single issue per problem and feature request.
Do not enumerate multiple bugs or feature requests in the same issue.
The more information you can provide, the more likely someone will be successful at reproducing the issue and finding a fix.
Please include the following with each issue:
* Version of IQ#
* Your operating system
* Reproducible steps (1... 2... 3...) that cause the issue
* What you expected to happen, versus what actually happened
## Contributing Documentation
If you are interested in contributing to conceptual documentation about IQ#, please see the [MicrosoftDocs/quantum-docs-pr](https://github.com/MicrosoftDocs/quantum-docs-pr) repository.
If you are interested in contributing API references, please see [Contributing Code](https://docs.microsoft.com/quantum/contributing/code) in the contribution guide.
## Contributing Fixes and New Features
If you are interested in writing code to fix issues or to implement new features, please see [Contributing Code](https://docs.microsoft.com/quantum/contributing/code) in the contribution guide.
# Thank You!
Your contributions to open source, large or small, make great projects like this possible.
Thank you for taking the time to contribute.

21
LICENSE Normal file
Просмотреть файл

@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

377
NOTICE.txt Normal file
Просмотреть файл

@ -0,0 +1,377 @@
NOTICES AND INFORMATION
Do Not Translate or Localize
This software incorporates material from third parties.
Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
or you may send a check or money order for US $5.00, including the product name,
the open source component name, and version number, to:
Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA
Notwithstanding any other terms, you may reverse engineer this software to the extent
required to debug changes to any libraries licensed under the GNU Lesser General Public License.
-------------------------------------------------------------------
McMaster.Extensions.CommandLineUtils 2.2.5 - Apache-2.0
(c) 2008 VeriSign, Inc.
Copyright Nate McMaster
Copyright (c) Nate McMaster
Copyright Nate McMaster YCommand-line
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-------------------------------------------------------------------
-------------------------------------------------------------------
FParsec 1.0.3 - BSD-2-Clause
(c) 2008 VeriSign, Inc.
Copyright Stephan Tolksdorf
Copyright (c) Stephan Tolksdorf
Copyright Stephan Tolksdorf FParsec
Copyright Stephan Tolksdorf FParsecCS
Copyright Stephan Tolksdorf VarFileInfo
Copyright (c) <year> <owner> . All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
-------------------------------------------------------------------
Markdig 0.16.0 - BSD-2-Clause
(c) 2008 VeriSign, Inc.
Copyright (c) <year> <owner> . All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
-------------------------------------------------------------------
FSharp.Core 4.6.2 - MIT
(c) 2008 VeriSign, Inc.
(c) Microsoft Corporation.
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
Microsoft.Jupyter.Core 1.1.14623 - MIT
(c) 2008 VeriSign, Inc.
(c) Microsoft Corporation.
Copyright (c) Microsoft Corporation.
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
Newtonsoft.Json 12.0.1 - MIT
(c) 2008 VeriSign, Inc.
Copyright James Newton-King 2008
Copyright (c) 2007 James Newton-King
Copyright (c) James Newton-King 2008
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
Newtonsoft.Json.Bson 1.0.2 - MIT
(c) 2008 VeriSign, Inc.
Copyright James Newton-King 2017
Copyright (c) 2017 James Newton-King
Copyright (c) James Newton-King 2017
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
System.Configuration.ConfigurationManager 4.5.0 - MIT
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
System.ServiceModel.Primitives 4.5.3 - MIT
(c) 2008 VeriSign, Inc.
(c) Microsoft Corporation.
Copyright (c) .NET Foundation and Contributors
Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
YamlDotNet 6.0.0 - MIT
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------

3
PRIVACY.md Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Data Collection #
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.

84
README.md Normal file
Просмотреть файл

@ -0,0 +1,84 @@
# Microsoft Quantum Development Kit: IQ# Kernel #
Welcome to the Microsoft Quantum Development Kit!
This repository contains the IQ# kernel for the [Quantum Development Kit](https://docs.microsoft.com/quantum/).
This kernel provides Q# support for the Jupyter platform, as well as the backend used by the Python client for Q#.
- **[Jupyter/](./tree/master/Jupyter/)**: Assembly used to interoperate between Jupyter and the rest of the IQ# kernel.
- **[Src/](./tree/master/Src/)**: Core of the IQ# kernel.
- **[Tests/](./tree/master/Tests/)**: Unit tests for IQ#.
- **[Tool/](./tree/master/Tool/)**: .NET Core Global Tool used to install and launch IQ#.
- **[Web/](./tree/master/Web/)**: Provides a RESTful API into IQ#.
## New to Quantum? ##
See the [introduction to quantum computing](https://docs.microsoft.com/quantum/concepts/) provided with the Quantum Development Kit.
## Getting Started ##
The Jupyter kernel provided in this repository is built using [.NET Core](https://docs.microsoft.com/dotnet/core/) (2.2 or later) and the compiler infrastructure provided with the [Quantum Development Kit](https://docs.microsoft.com/quantum/).
Please see the [getting started guide](https://docs.microsoft.com/quantum/install-guide) for how to get up and running.
You may also visit the [**microsoft/quantum**](https://github.com/microsoft/quantum) repository, which offers a wide variety
of samples on how to use this kernel to run Q# in Jupyter Notebooks, or from Python.
### Building IQ# from Source ###
To build IQ# from Visual Studio 2017 or later, please use the [`iqsharp.sln`](./blob/master/iqsharp.sln) solution file.
To build using the .NET Core SDK, please run `dotnet build iqsharp.sln`.
In either case, the IQ# kernel can be installed by using `dotnet run`:
```
cd src/Tool/
dotnet run -- install
```
Optionally, you can install IQ# in _development mode_, which instructs the Jupyter platform to rebuild IQ# whenever a new kernel is started:
```
cd src/Tool/
dotnet run -- install --develop
```
This can cause some issues, especially when running multiple instances of IQ#, such that we recommend against using development mode in general usage.
## Build Status ##
| branch | status |
|--------|-----------|
| master | [![Build Status](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_apis/build/status/microsoft.iqsharp?branchName=master)](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_build/latest?definitionId=14&branchName=master) |
## Feedback ##
If you have feedback about IQ#, please let us know by filing a [new issue](https://github.com/microsoft/iqsharp/issues/new)!
If you have feedback about some other part of the Microsoft Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/quantum/contributing/) for more information.
## Legal and Licensing ##
### Telemetry ###
By default, IQ# collects information about the runtime performance of IQ#.
To opt-out of sending telemetry, create an environment variable called IQSHARP_TELEMETRY_OPT_OUT set to a value of 1 before starting IQ#.
The telemetry we collect falls under the [Microsoft Privacy Statement](https://privacy.microsoft.com/privacystatement).
### Data Collection ###
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
## Contributing ##
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
For more details, please see [CONTRIBUTING.md](./tree/master/CONTRIBUTING.md), or the [contribution guide](https://docs.microsoft.com/quantum/contributing/).

17
bootstrap.ps1 Normal file
Просмотреть файл

@ -0,0 +1,17 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# If the compiler constants include TELEMETRY, explicitly add the Aria telemetry package to the iqsharp tool:
if (($Env:ASSEMBLY_CONSTANTS -ne $null) -and ($Env:ASSEMBLY_CONSTANTS.Contains("TELEMETRY"))) {
$project = (Join-Path $PSScriptRoot 'src\Tool\Tool.csproj')
$pkg = "Microsoft.Applications.Events.Server.Core2"
Write-Host "##[info]Adding $pkg to $project"
dotnet add $project `
package $pkg `
--no-restore `
--version "0.92.6"
}

27
build/DelaySign.cs Normal file
Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Reflection;
// Attributes for delay-signing
#if SIGNED
[assembly:AssemblyKeyFile("..\\..\\build\\267DevDivSNKey2048.snk")]
[assembly:AssemblyDelaySign(true)]
#endif
internal static class SigningConstants
{
#if SIGNED
public const string PUBLIC_KEY = ", PublicKey=" +
"002400000c800000140100000602000000240000525341310008000001000100613399aff18ef1" +
"a2c2514a273a42d9042b72321f1757102df9ebada69923e2738406c21e5b801552ab8d200a65a2" +
"35e001ac9adc25f2d811eb09496a4c6a59d4619589c69f5baf0c4179a47311d92555cd006acc8b" +
"5959f2bd6e10e360c34537a1d266da8085856583c85d81da7f3ec01ed9564c58d93d713cd0172c" +
"8e23a10f0239b80c96b07736f5d8b022542a4e74251a5f432824318b3539a5a087f8e53d2f135f" +
"9ca47f3bb2e10aff0af0849504fb7cea3ff192dc8de0edad64c68efde34c56d302ad55fd6e80f3" +
"02d5efcdeae953658d3452561b5f36c542efdbdd9f888538d374cef106acf7d93a4445c3c73cd9" +
"11f0571aaf3d54da12b11ddec375b3";
#else
public const string PUBLIC_KEY = "";
#endif
}

33
build/build.ps1 Normal file
Просмотреть файл

@ -0,0 +1,33 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
$ErrorActionPreference = 'Stop'
& "$PSScriptRoot/set-env.ps1"
$all_ok = $True
function Build-One {
param(
[string]$action,
[string]$project
);
Write-Host "##[info]Building $project"
dotnet $action (Join-Path $PSScriptRoot $project) `
-c $Env:BUILD_CONFIGURATION `
-v $Env:BUILD_VERBOSITY `
/property:DefineConstants=$Env:ASSEMBLY_CONSTANTS `
/property:Version=$Env:ASSEMBLY_VERSION `
/property:QsharpDocsOutDir=$Env:DOCS_OUTDIR
$script:all_ok = ($LastExitCode -eq 0) -and $script:all_ok
}
Build-One build '../iqsharp.sln'
if (-not $all_ok)
{
throw "At least one project failed to compile. Check the logs."
}

17
build/ci.yml Normal file
Просмотреть файл

@ -0,0 +1,17 @@
name: $(Build.Major).$(Build.Minor).$(date:yyMM).$(DayOfMonth)$(rev:rr)
trigger:
- master
variables:
Build.Major: 0
Build.Minor: 0
Drops.Dir: $(Build.ArtifactStagingDirectory)/drops
jobs:
- job: "iqsharp"
steps:
- template: steps.yml
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection'
inputs:
failOnAlert: true

88
build/pack.ps1 Normal file
Просмотреть файл

@ -0,0 +1,88 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
$ErrorActionPreference = 'Stop'
& "$PSScriptRoot/set-env.ps1"
$all_ok = $True
function Pack-Nuget() {
param(
[string]$project
);
dotnet pack (Join-Path $PSScriptRoot $project) `
--no-build `
-c $Env:BUILD_CONFIGURATION `
-v $Env:BUILD_VERBOSITY `
-o $Env:NUGET_OUTDIR `
/property:Version=$Env:ASSEMBLY_VERSION `
/property:PackageVersion=$Env:NUGET_VERSION
$script:all_ok = ($LastExitCode -eq 0) -and $script:all_ok
}
function Pack-Wheel() {
param(
[string] $Path
);
$result = 0
Push-Location (Join-Path $PSScriptRoot $Path)
python setup.py bdist_wheel
$result = $LastExitCode
Copy-Item "dist/*.whl" $Env:PYTHON_OUTDIR
Pop-Location
$script:all_ok = ($LastExitCode -eq 0) -and $script:all_ok
}
function Pack-Image() {
param(
[string] $RepoName,
[string] $Dockerfile
);
if (($Env:AGENT_OS -ne $null) -and ($Env:AGENT_OS.StartsWith("Win"))) {
Write-Host "##vso[task.logissue type=warning;]cannot create docker image on Windows."
return
}
Try {
docker version
} Catch {
Write-Host "##vso[task.logissue type=warning;]docker not installed. Will skip creation of image for $Dockerfile"
return
}
docker build `
<# We treat $DROP_DIR as the build context, as we will need to ADD
nuget packages into the image. #> `
$Env:DROPS_DIR `
<# This means that the Dockerfile lives outside the build context. #> `
-f (Join-Path $PSScriptRoot $Dockerfile) `
<# Next, we tell Docker what version of IQ# to install. #> `
--build-arg IQSHARP_VERSION=$Env:NUGET_VERSION `
<# Finally, we tag the image with the current build number. #> `
-t "${Env:DOCKER_PREFIX}${RepoName}:${Env:BUILD_BUILDNUMBER}"
$script:all_ok = ($LastExitCode -eq 0) -and $script:all_ok
}
Write-Host "##[info]Packing IQ# library..."
Pack-Nuget '../src/Core/Core.csproj'
Write-Host "##[info]Packing IQ# tool..."
Pack-Nuget '../src/Tool/Tool.csproj'
Write-Host "##[info]Packing Python wheel..."
python --version
Pack-Wheel '../src/Python/'
Write-Host "##[info]Packing Docker image..."
Pack-Image -RepoName "iqsharp-base" -Dockerfile '../images/iqsharp-base/Dockerfile'
if (-not $all_ok) {
throw "At least one package failed to build. Check the logs."
}

26
build/set-env.ps1 Normal file
Просмотреть файл

@ -0,0 +1,26 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
$ErrorActionPreference = 'Stop'
Write-Host "Setting up build environment variables"
If ($Env:BUILD_BUILDNUMBER -eq $null) { $Env:BUILD_BUILDNUMBER = "0.0.1.0" }
If ($Env:BUILD_CONFIGURATION -eq $null) { $Env:BUILD_CONFIGURATION = "Debug"}
If ($Env:BUILD_VERBOSITY -eq $null) { $Env:BUILD_VERBOSITY = "m"}
If ($Env:ASSEMBLY_VERSION -eq $null) { $Env:ASSEMBLY_VERSION = "$Env:BUILD_BUILDNUMBER"}
If ($Env:NUGET_VERSION -eq $null) { $Env:NUGET_VERSION = "$Env:ASSEMBLY_VERSION-alpha"}
If ($Env:PYTHON_VERSION -eq $null) { $Env:PYTHON_VERSION = "${Env:ASSEMBLY_VERSION}a1" }
if ($Env:DOCKER_PREFIX -eq $null) { $Env:DOCKER_PREFIX = "" }
If ($Env:DROPS_DIR -eq $null) { $Env:DROPS_DIR = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\drops")) }
If ($Env:NUGET_OUTDIR -eq $null) { $Env:NUGET_OUTDIR = (Join-Path $Env:DROPS_DIR "nugets") }
If (-not (Test-Path -Path $Env:NUGET_OUTDIR)) { [IO.Directory]::CreateDirectory($Env:NUGET_OUTDIR) }
If ($Env:PYTHON_OUTDIR -eq $null) { $Env:PYTHON_OUTDIR = (Join-Path $Env:DROPS_DIR "wheels") }
If (-not (Test-Path -Path $Env:PYTHON_OUTDIR)) { [IO.Directory]::CreateDirectory($Env:PYTHON_OUTDIR) }
If ($Env:DOCS_OUTDIR -eq $null) { $Env:DOCS_OUTDIR = (Join-Path $Env:DROPS_DIR "docs") }
If (-not (Test-Path -Path $Env:DOCS_OUTDIR)) { [IO.Directory]::CreateDirectory($Env:DOCS_OUTDIR) }

50
build/steps.yml Normal file
Просмотреть файл

@ -0,0 +1,50 @@
##
# Build and test IQ#.
##
steps:
##
# Pre-reqs
##
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
architecture: 'x64'
displayName: 'Use Python 3.6'
- script: pip install setuptools wheel pytest jupyter
displayName: 'Install Python tools'
##
# Build, test & pack
##
- powershell: .\build.ps1
displayName: "Building IQ#"
workingDirectory: '$(System.DefaultWorkingDirectory)/build'
- powershell: .\test.ps1
displayName: "Testing IQ#"
workingDirectory: '$(System.DefaultWorkingDirectory)/build'
condition: and(succeeded(), ne(variables['Skip.Tests'], 'true'))
- powershell: .\pack.ps1
displayName: "Packing IQ#"
workingDirectory: '$(System.DefaultWorkingDirectory)/build'
##
# Publish tests results and build artifacts.
##
- task: PublishTestResults@2
displayName: 'Publish IQ# tests results'
condition: succeededOrFailed()
inputs:
testResultsFormat: VSTest
testResultsFiles: '$(System.DefaultWorkingDirectory)/**/*.trx'
testRunTitle: 'IQ# tests'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'
condition: succeededOrFailed()
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: iqsharp

31
build/test.ps1 Normal file
Просмотреть файл

@ -0,0 +1,31 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
$ErrorActionPreference = 'Stop'
& "$PSScriptRoot/set-env.ps1"
$all_ok = $True
Write-Host "Testing IQ#:"
function Test-One {
Param($project)
Write-Host "##[info]Testing $project"
dotnet test $project `
-c $Env:BUILD_CONFIGURATION `
-v $Env:BUILD_VERBOSITY `
--logger trx `
/property:DefineConstants=$Env:ASSEMBLY_CONSTANTS `
/property:Version=$Env:ASSEMBLY_VERSION
$script:all_ok = ($LastExitCode -eq 0) -and $script:all_ok
}
Test-One '../iqsharp.sln'
if (-not $all_ok)
{
throw "At least one project failed to compile. Check the logs."
}

Просмотреть файл

@ -0,0 +1,101 @@
# The same image used by mybinder.org
FROM python:3.7-slim
# install the notebook package
RUN pip install --no-cache --upgrade pip && \
pip install --no-cache notebook
# Install APT prerequisites.
RUN apt-get update && \
apt-get -y install \
# Dependencies for the .NET Core SDK.
wget \
pgp \
vim \
apt-transport-https \
# Dependencies for the Quantum Development Kit.
# Note that we install them here to minimize the number
# of layers.
libgomp1 \
# Not strictly needed, but Git is useful for several
# interactive scenarios, so we finish by adding it as
# well. Thankfully, Git is a small dependency (~3 MiB)
# given what we have already installed.
git && \
# We clean the apt cache at the end of each apt command so that the caches
# don't get stored in each layer.
apt-get clean && rm -rf /var/lib/apt/lists/
# Trim down the size of the container by disabling the offline package
# cache. See also: https://github.com/dotnet/dotnet-docker/issues/237
ENV NUGET_XMLDOC_MODE=skip \
DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
# Now that we have all the dependencies in place, we install the .NET Core SDK itself.
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg && \
mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/ && \
wget -q https://packages.microsoft.com/config/debian/9/prod.list && \
mv prod.list /etc/apt/sources.list.d/microsoft-prod.list && \
chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg && \
chown root:root /etc/apt/sources.list.d/microsoft-prod.list && \
apt-get -y update && \
apt-get -y install dotnet-sdk-2.2 && \
apt-get clean && rm -rf /var/lib/apt/lists/
# create user with a home directory
# Required for mybinder.org
ARG NB_USER=jovyan
ARG NB_UID=1000
ENV USER=${NB_USER} \
UID=${NB_UID} \
HOME=/home/${NB_USER} \
IQSHARP_HOSTING_ENV=iqsharp-base \
# Some ways of invoking this image will look at the $SHELL environment
# variable instead of chsh, so we set the new user's shell here as well.
SHELL=/bin/bash
RUN adduser --disabled-password \
--gecos "Default user" \
--uid ${UID} \
${USER} && \
# Set the new user's shell to be bash when logging in interactively.
chsh -s /bin/bash ${USER}
WORKDIR ${HOME}
# Provide local copies of all relevant packages.
ENV LOCAL_PACKAGES=${HOME}/.packages
# Add the local NuGet packages folder as a source.
RUN mkdir -p ${HOME}/.nuget/NuGet && \
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\
<configuration>\n\
<packageSources>\n\
<add key=\"nuget\" value=\"https://api.nuget.org/v3/index.json\" />\n\
<add key=\"context\" value=\"${LOCAL_PACKAGES}/nugets\" />\n\
</packageSources>\n\
</configuration>\n\
" > ${HOME}/.nuget/NuGet/NuGet.Config
# Add Python and NuGet packages from the build context
ADD nugets/*.nupkg ${LOCAL_PACKAGES}/nugets/
ADD wheels/*.whl ${LOCAL_PACKAGES}/wheels/
# Give the notebook user ownership over the packages and config copied from
# the context.
RUN chown ${USER} -R ${LOCAL_PACKAGES}/ && \
chown ${USER} -R ${LOCAL_PACKAGES}/ ${HOME}/.nuget
# Install all wheels from the build context.
RUN pip install $(ls ${LOCAL_PACKAGES}/wheels/*.whl)
# Switch to the notebook user to finish the installation.
USER ${USER}
# Make sure that .NET Core is on the notebook users' path.
ENV PATH=$PATH:${HOME}/dotnet:${HOME}/.dotnet/tools \
DOTNET_ROOT=${HOME}/dotnet
# Install IQ# and the project templates, using the NuGet packages from the
# build context.
ARG IQSHARP_VERSION
RUN dotnet new -i "Microsoft.Quantum.ProjectTemplates::0.8.1906.1704-beta" && \
dotnet tool install \
--global \
Microsoft.Quantum.IQSharp \
--version ${IQSHARP_VERSION}
RUN dotnet iqsharp install --user --path-to-tool="$(which dotnet-iqsharp)"

90
iqsharp.sln Normal file
Просмотреть файл

@ -0,0 +1,90 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jupyter", "src\Jupyter\Jupyter.csproj", "{B6F42099-DACD-472F-866C-BEF92DDDF754}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{0ACA57A6-A8F6-497C-85D3-D547433BFACB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.IQsharp", "src\Tests\Tests.IQsharp.csproj", "{756BE082-2E89-47F0-A48A-D7E762B0A82E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tool", "src\Tool\Tool.csproj", "{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{6431E92B-12AA-432C-8D53-C9A7A54BA21B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|x64.ActiveCfg = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|x64.Build.0 = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|x86.ActiveCfg = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Debug|x86.Build.0 = Debug|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|Any CPU.Build.0 = Release|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|x64.ActiveCfg = Release|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|x64.Build.0 = Release|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|x86.ActiveCfg = Release|Any CPU
{B6F42099-DACD-472F-866C-BEF92DDDF754}.Release|x86.Build.0 = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|x64.ActiveCfg = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|x64.Build.0 = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|x86.ActiveCfg = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Debug|x86.Build.0 = Debug|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|Any CPU.Build.0 = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|x64.ActiveCfg = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|x64.Build.0 = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|x86.ActiveCfg = Release|Any CPU
{0ACA57A6-A8F6-497C-85D3-D547433BFACB}.Release|x86.Build.0 = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|x64.ActiveCfg = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|x64.Build.0 = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|x86.ActiveCfg = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Debug|x86.Build.0 = Debug|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|Any CPU.Build.0 = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|x64.ActiveCfg = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|x64.Build.0 = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|x86.ActiveCfg = Release|Any CPU
{756BE082-2E89-47F0-A48A-D7E762B0A82E}.Release|x86.Build.0 = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|x64.ActiveCfg = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|x64.Build.0 = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|x86.ActiveCfg = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Debug|x86.Build.0 = Debug|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|Any CPU.Build.0 = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|x64.ActiveCfg = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|x64.Build.0 = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|x86.ActiveCfg = Release|Any CPU
{7EB9C7E8-7D40-432E-9857-1DD6301B9F4A}.Release|x86.Build.0 = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|x64.ActiveCfg = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|x64.Build.0 = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|x86.ActiveCfg = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Debug|x86.Build.0 = Debug|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|Any CPU.Build.0 = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|x64.ActiveCfg = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|x64.Build.0 = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|x86.ActiveCfg = Release|Any CPU
{6431E92B-12AA-432C-8D53-C9A7A54BA21B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

108
src/Core/AssemblyInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Quantum.QsCompiler.CompilationBuilder;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// This class stores the information about a .net core assembly.
/// If the assembly was built from Q# code, then it also keeps track of the list of Operations
/// defined in it, plus the corresponding SyntaxTree.
/// </summary>
public class AssemblyInfo : IEquatable<AssemblyInfo>
{
/// List of operations found. Calculated on demand.
private Lazy<OperationInfo[]> _operations;
/// <summary>
/// Constructor for non Q# compiled assemblies.
/// </summary>
public AssemblyInfo(Assembly assembly) : this(assembly, location: null, syntaxTree: null)
{
}
/// <summary>
/// Constructor for Q# compiled assemblies.
/// </summary>
public AssemblyInfo(Assembly assembly, string location, QsNamespace[] syntaxTree)
{
Assembly = assembly;
Location = location ?? assembly?.Location;
SyntaxTree = syntaxTree;
_operations = new Lazy<OperationInfo[]>(InitOperations);
}
/// <summary>
/// The actual Assembly we're wrapping.
/// </summary>
public Assembly Assembly { get; }
/// <summary>
/// The path (location) in disk of this assembly.
/// </summary>
public string Location { get; }
/// <summary>
/// For Q#-based assemblies, the corresponding SyntaxTree.
/// </summary>
public QsNamespace[] SyntaxTree { get; }
/// <summary>
/// For Q#-based assemblies, the corresponding operations found in the SyntaxTree.
/// </summary>
public IEnumerable<OperationInfo> Operations => _operations.Value;
/// <summary>
/// Used to lazily calculate operations in an assembly.
/// Assumes that all Types in the Assembly are for operations.
/// </summary>
private OperationInfo[] InitOperations()
{
if (Assembly == null) return new OperationInfo[0];
// Parse the assembly headers to find which types are operation or function types.
var logger = new QSharpLogger(null);
var refs = ProjectManager.LoadReferencedAssemblies(new[] { Location }, d => logger.Log(d), ex => logger.Log(ex));
System.Diagnostics.Debug.Assert(refs.Declarations.Count == 1);
var headers = refs.Declarations.Values.First();
var ops = new List<OperationInfo>();
foreach (var header in headers.Callables)
{
// Find the associated type.
var fullName = header.QualifiedName.ToFullName();
var type = Assembly.GetType(fullName);
var info = new OperationInfo(type, header);
ops.Add(info);
}
return ops.ToArray();
}
#region Equals
public override string ToString() => Assembly?.ToString();
public override bool Equals(object obj) => Equals(obj as AssemblyInfo);
public bool Equals(AssemblyInfo other) => Assembly?.FullName == other?.Assembly?.FullName;
public override int GetHashCode() => Assembly?.FullName?.GetHashCode() ?? 0;
public static bool operator ==(AssemblyInfo info1, AssemblyInfo info2) => info1?.Assembly?.FullName == info2?.Assembly?.FullName;
public static bool operator !=(AssemblyInfo info1, AssemblyInfo info2) => !(info1 == info2);
#endregion
public static AssemblyInfo Create(Assembly assembly) => assembly == null ? null : new AssemblyInfo(assembly);
}
}

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Represents information that the kernel has about the client connected
/// to IQ#.
/// </summary>
public class ClientInformation
{
/// <summary>
/// A string passed by the client representing the name of the client.
/// </summary>
public string UserAgent { get; set; }
/// <summary>
/// A string passed by the client representing the enviornment in which
/// the client is running (e.g.: continuous integration, a hosted
/// notebook service, etc.).
/// </summary>
public string HostingEnvironment { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.Quantum.QsCompiler.CompilationBuilder;
using Microsoft.Quantum.IQSharp.Common;
using QsReferences = Microsoft.Quantum.QsCompiler.CompilationBuilder.References;
namespace Microsoft.Quantum.IQSharp
{
public class CompilerMetadata
{
private IEnumerable<String> Paths { get; }
/// <summary>
/// The list of Assemblies and their dependencies in the format the C# compiler (Roslyn) expects them.
/// </summary>
public IEnumerable<MetadataReference> RoslynMetadatas { get; }
/// <summary>
/// The list of Assemblies and their dependencies in the format the Q# compiler expects them.
/// </summary>
public QsReferences QsMetadatas { get; }
public CompilerMetadata(IEnumerable<AssemblyInfo> assemblies)
{
Paths = PathsInit(assemblies);
RoslynMetadatas = RoslynInit(Paths);
QsMetadatas = QsInit(Paths);
}
private CompilerMetadata(IEnumerable<String> paths, IEnumerable<MetadataReference> roslyn, QsReferences qsharp)
{
Paths = paths;
RoslynMetadatas = roslyn;
QsMetadatas = qsharp;
}
/// <summary>
/// Calculates the paths for all the Assemblies and their dependencies.
/// </summary>
private static List<string> PathsInit(IEnumerable<AssemblyInfo> assemblies, IEnumerable<string> seed = null)
{
var found = new List<string>(seed ?? Enumerable.Empty<string>());
foreach (var a in assemblies)
{
AddReferencesPaths(found, a.Assembly, a.Location);
}
return found;
}
private static void AddReferencesPaths(List<string> found, Assembly asm, string location)
{
if (string.IsNullOrEmpty(location)) return;
if (found.Contains(location))
{
return;
}
found.Add(location);
foreach (var a in asm.GetReferencedAssemblies())
{
try
{
var assm = Assembly.Load(a);
AddReferencesPaths(found, assm, assm.Location);
}
catch (Exception)
{
//Ignore assembly if it can't be loaded.
}
}
}
/// <summary>
/// Calculates Roslyn's MetadataReference for all the Assemblies and their dependencies.
/// </summary>
private static ImmutableArray<MetadataReference> RoslynInit(IEnumerable<string> paths)
{
var mds = paths.Select(p => MetadataReference.CreateFromFile(p));
return mds.Select(a => a as MetadataReference).ToImmutableArray();
}
/// <summary>
/// Calculates Q# metadata needed for all the Assemblies and their dependencies.
/// </summary>
private static QsReferences QsInit(IEnumerable<string> paths) =>
ProjectManager.LoadReferencedAssemblies(paths);
public CompilerMetadata WithAssemblies(params AssemblyInfo[] assemblies)
{
var extraPaths = PathsInit(assemblies, Paths);
var extraRoslyn = RoslynInit(extraPaths);
var extraQsharp = QsInit(Paths.Union(extraPaths));
return new CompilerMetadata(extraPaths, extraRoslyn, extraQsharp);
}
}
}

Просмотреть файл

@ -0,0 +1,175 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.QsCompiler.CompilationBuilder;
using Microsoft.Quantum.QsCompiler.CsharpGeneration;
using Microsoft.Quantum.QsCompiler.DataTypes;
using QsReferences = Microsoft.Quantum.QsCompiler.CompilationBuilder.References;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Default implementation of ICompilerService.
/// This service is capable of building .net core assemblies on the fly from Q# code.
/// </summary>
public class CompilerService : ICompilerService
{
/// <summary>
/// Builds the corresponding .net core assembly from the code in the given Q# Snippets.
/// Each snippet code is wrapped inside the 'SNIPPETS_NAMESPACE' namespace and processed as a file
/// with the same name as the snippet id.
/// </summary>
public AssemblyInfo BuildSnippets(Snippet[] snippets, CompilerMetadata metadatas, QSharpLogger logger, string dllName)
{
string WrapInNamespace(Snippet s) => $"namespace {Snippets.SNIPPETS_NAMESPACE} {{ open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; {s.code} }}";
var sources = snippets.ToDictionary(s => s.Uri, WrapInNamespace);
var syntaxTree = BuildQsSyntaxTree(sources.ToImmutableDictionary(), metadatas.QsMetadatas, logger);
var assembly = BuildAssembly(sources.Keys.ToArray(), syntaxTree, metadatas.RoslynMetadatas, logger, dllName);
return assembly;
}
/// <summary>
/// Compiles the given Q# code and returns the list of elements found in it.
/// The compiler does this on a best effort, so it will return the elements even if the compilation fails.
/// </summary>
public IEnumerable<QsCompiler.SyntaxTree.QsNamespaceElement> IdentifyElements(string source)
{
var ns = NonNullable<string>.New(Snippets.SNIPPETS_NAMESPACE);
var logger = new QSharpLogger(null);
var sources = new Dictionary<Uri, string>() { { new Uri($"file:///temp"), $"namespace {ns.Value} {{ {source} }}" } }.ToImmutableDictionary();
var references = QsReferences.Empty;
var loadOptions = new QsCompiler.CompilationLoader.Configuration(); // do not generate functor support
var loaded = new QsCompiler.CompilationLoader(_ => sources, _ => references, loadOptions, logger);
return loaded.VerifiedCompilation?.SyntaxTree[ns].Elements;
}
/// <summary>
/// Builds the corresponding .net core assembly from the code in the given files.
/// </summary>
public AssemblyInfo BuildFiles(string[] files, CompilerMetadata metadatas, QSharpLogger logger, string dllName)
{
var syntaxTree = BuildQsSyntaxTree(files, metadatas.QsMetadatas, logger);
Uri FileUri(string f) => CompilationUnitManager.TryGetUri(NonNullable<string>.New(f), out var uri) ? uri : null;
var assembly = BuildAssembly(files.Select(FileUri) .ToArray(), syntaxTree, metadatas.RoslynMetadatas, logger, dllName);
return assembly;
}
/// <summary>
/// Builds the Q# syntax tree from the given files.
/// The files are given as a list of filenames, as per the format expected by
/// the <see cref="Microsoft.Quantum.QsCompiler.CompilationBuilder.ProjectManager.LoadSourceFiles(IEnumerable{string}, Action{VisualStudio.LanguageServer.Protocol.Diagnostic}, Action{Exception})" />
/// method.
/// </summary>
private static QsCompiler.SyntaxTree.QsNamespace[] BuildQsSyntaxTree(string[] files, QsReferences references, QSharpLogger logger)
{
var sources = ProjectManager.LoadSourceFiles(files, d => logger?.Log(d), ex => logger?.Log(ex));
return BuildQsSyntaxTree(sources, references, logger);
}
/// <summary>
/// Builds the Q# syntax tree from the given files/source paris.
/// </summary>
private static QsCompiler.SyntaxTree.QsNamespace[] BuildQsSyntaxTree(ImmutableDictionary<Uri, string> sources, QsReferences references, QSharpLogger logger)
{
var loadOptions = new QsCompiler.CompilationLoader.Configuration { GenerateFunctorSupport = true };
var loaded = new QsCompiler.CompilationLoader(_ => sources, _ => references, loadOptions, logger);
return loaded.GeneratedSyntaxTree?.ToArray();
}
/// <summary>
/// Builds the corresponding .net core assembly from the Q# syntax tree.
/// </summary>
private static AssemblyInfo BuildAssembly(Uri[] fileNames, QsCompiler.SyntaxTree.QsNamespace[] syntaxTree, IEnumerable<MetadataReference> references, QSharpLogger logger, string targetDll)
{
if (logger.HasErrors) return null;
logger.LogDebug($"Compiling the following Q# files: {string.Join(",", fileNames.Select(f => f.LocalPath))}");
try
{
// Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees:
var trees = new List<SyntaxTree>();
NonNullable<string> GetFileId(Uri uri) => CompilationUnitManager.TryGetFileId(uri, out var id) ? id : NonNullable<string>.New(uri.AbsolutePath);
foreach (var file in fileNames)
{
var sourceFile = GetFileId(file);
var code = SimulationCode.generate(sourceFile, syntaxTree);
var tree = CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8);
trees.Add(tree);
logger.LogDebug($"Generated the following C# code for {sourceFile.Value}:\n=============\n{code}\n=============\n");
}
// Compile the C# syntax trees:
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);
var compilation = CSharpCompilation.Create(
Path.GetFileNameWithoutExtension(targetDll),
trees,
references,
options);
// Generate the assembly from the C# compilation:
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
logger.LogError("IQS000", "Could not compile Roslyn dll from working folder.");
foreach (Diagnostic diagnostic in failures)
{
logger.LogError(diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
else
{
logger.LogDebug($"Assembly successfully generated. Caching at {targetDll}.");
var data = ms.ToArray();
try
{
File.WriteAllBytes(targetDll, data);
}
catch (Exception e)
{
logger.LogError("IQS001", $"Unable to save assembly cache: {e.Message}.");
}
return new AssemblyInfo(Assembly.Load(data), targetDll, syntaxTree);
}
}
}
catch (Exception e)
{
logger.LogError("IQS002", $"Unexpected error compiling assembly: {e.Message}.");
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// This service is capable of building .net core assemblies on the fly from Q# code.
/// </summary>
public interface ICompilerService
{
/// <summary>
/// Builds the corresponding .net core assembly from the code in the given Q# Snippets.
/// </summary>
AssemblyInfo BuildSnippets(Snippet[] snippets, CompilerMetadata metadatas, QSharpLogger logger, string dllName);
/// <summary>
/// Builds the corresponding .net core assembly from the code in the given files.
/// </summary>
AssemblyInfo BuildFiles(string[] files, CompilerMetadata metadatas, QSharpLogger logger, string dllName);
/// <summary>
/// Compiles the given Q# code and returns the list of elements found in it.
/// The compiler does this on a best effort, so it will return the elements even if the compilation fails.
/// </summary>
IEnumerable<QsCompiler.SyntaxTree.QsNamespaceElement> IdentifyElements(string source);
}
}

44
src/Core/Core.csproj Normal file
Просмотреть файл

@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>Microsoft.Quantum.IQSharp</RootNamespace>
<AssemblyName>Microsoft.Quantum.IQSharp.Core</AssemblyName>
</PropertyGroup>
<PropertyGroup>
<NoWarn>0162</NoWarn>
<Authors>Microsoft</Authors>
<Description>Microsoft's IQ# Library.</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageReleaseNotes>See: https://docs.microsoft.com/en-us/quantum/relnotes/</PackageReleaseNotes>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/Microsoft/Quantum</PackageProjectUrl>
<PackageIconUrl>https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png</PackageIconUrl>
<PackageTags>Quantum Q# Qsharp</PackageTags>
<PackageId>Microsoft.Quantum.IQSharp.Core</PackageId>
<ContentTargetFolders>\</ContentTargetFolders>
<ApplicationIcon />
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\build\DelaySign.cs" Link="Properties\DelaySign.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\NOTICE.txt" Link="NOTICE.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageReference Include="Microsoft.Quantum.Compiler" Version="0.8.1906.1704-beta" />
<PackageReference Include="Microsoft.Quantum.CsharpGeneration" Version="0.8.1906.1704-beta" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.8.1906.1704-beta" />
<PackageReference Include="NuGet.Resolver" Version="5.1.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.Quantum.IQSharp.Common
{
public class CompilationErrorsException : InvalidOperationException
{
public CompilationErrorsException(string[] errors) : base("Invalid snippet code")
{
this.Errors = errors;
}
public string[] Errors { get; }
}
}

Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.Quantum.IQSharp.Common
{
/// <summary>
/// This Exception gets triggered whenever the user tries to access operations
/// on the current Workspace, but the Workspace was not correctly built.
/// </summary>
public class InvalidWorkspaceException : InvalidOperationException
{
public InvalidWorkspaceException(params string[] errors) : base("Invalid workspace")
{
this.Errors = errors;
}
public string[] Errors { get; }
}
}

Просмотреть файл

@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using Microsoft.Quantum.QsCompiler.DataTypes;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.Simulation.Simulators;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Extensions for Q# components.
/// </summary>
public static partial class Extensions
{
public static readonly QsQualifiedName UNKNOWN_OPERATION = new QsQualifiedName(NonNullable<string>.New("UNKNOWN"), NonNullable<string>.New("UNKNOWN"));
/// <summary>
/// Returns the source of the given QsNamespaceElement (either QsCallable or QsCustomTypes)
/// </summary>
public static string SourceFile(this QsNamespaceElement e)
{
if (e is QsNamespaceElement.QsCallable c)
{
return c.Item.SourceFile.Value;
}
else if (e is QsNamespaceElement.QsCustomType t)
{
return t.Item.SourceFile.Value;
}
return "[Unknown]";
}
/// <summary>
/// Returns the name of the given QsNamespaceElement (either QsCallable or QsCustomTypes)
/// </summary>
public static string ToFullName(this QsNamespaceElement e)
{
var name = UNKNOWN_OPERATION;
if (e is QsNamespaceElement.QsCallable c)
{
name = c.Item.FullName;
}
else if (e is QsNamespaceElement.QsCustomType t)
{
name = t.Item.FullName;
}
return $"{name.Namespace.Value}.{name.Name.Value}";
}
/// <summary>
/// Formats a qualified name using dotted-name syntax.
/// <summary>
internal static string ToFullName(this QsQualifiedName name) =>
name?.Namespace.Value + "." + name?.Name.Value;
/// <summary>
/// Removes the given namespace, from the given name, iff name starts with namespace.
/// </summary>
public static string WithoutNamespace(this string name, string ns) => name.StartsWith(ns) ? name.Substring(ns.Length + 1) : name;
/// <summary>
/// Returns the ResourcesEstimator data as metric=value
/// </summary>
public static Dictionary<string, double> AsDictionary(this ResourcesEstimator qsim)
{
var counts = new Dictionary<string, double>();
foreach (DataRow row in qsim.Data.Rows)
{
string metric = (string)row["Metric"];
double data = (double)row["Sum"];
counts[metric] = data;
}
return counts;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Extensions for IServiceCollection
/// </summary>
public static partial class Extensions
{
public static void AddIQSharp(this IServiceCollection services)
{
services.AddSingleton<ICompilerService, CompilerService>();
services.AddSingleton<IOperationResolver, OperationResolver>();
services.AddSingleton<IReferences, References>();
services.AddSingleton<IWorkspace, Workspace>();
services.AddSingleton<ISnippets, Snippets>();
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Extensions for C# Types.
/// </summary>
public static partial class Extensions
{
private static Type WithoutTypeParameters(this Type type) =>
type.IsGenericType ? type.GetGenericTypeDefinition() : type;
internal static bool IsSubclassOfGenericType(this Type subType, Type baseType)
{
// Remove any type parameters of subType as applicable.
subType = subType?.WithoutTypeParameters();
if (subType == baseType)
{
return true;
}
else
{
// Check the next level up in inheritance from subtype, if it
// exists.
return subType?.BaseType?.IsSubclassOfGenericType(baseType) ?? false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Microsoft.Quantum.IQSharp.Common
{
/// <summary>
/// A simple class to keep track of Nuget logs.
/// </summary>
public class NuGetLogger : NuGet.Common.LoggerBase
{
private ILogger _logger { get; set; }
public List<NuGet.Common.ILogMessage> Logs { get; private set; }
public NuGetLogger(ILogger logger)
{
_logger = logger;
this.Logs = new List<NuGet.Common.ILogMessage>();
}
public static LogLevel MapLevel(NuGet.Common.LogLevel original)
{
switch (original)
{
case NuGet.Common.LogLevel.Error:
return LogLevel.Error;
case NuGet.Common.LogLevel.Warning:
return LogLevel.Warning;
case NuGet.Common.LogLevel.Information:
return LogLevel.Information;
case NuGet.Common.LogLevel.Debug:
return LogLevel.Debug;
default:
return LogLevel.Trace;
}
}
public override void Log(NuGet.Common.ILogMessage m)
{
_logger?.Log(MapLevel(m.Level), m.Message);
Logs.Add(m);
}
public override Task LogAsync(NuGet.Common.ILogMessage m)
{
Log(m);
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -0,0 +1,122 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.Quantum.IQSharp.Common
{
/// <summary>
/// This class is used to call the Q# compiler and:
/// 1. Delegate any messages to the .net core Logger
/// 2. Keep track of the messages so we can detect if there were any errors
/// </summary>
public class QSharpLogger : QsCompiler.Diagnostics.LogTracker
{
public ILogger Logger { get; }
public List<LSP.Diagnostic> Logs { get; }
public QSharpLogger(ILogger logger)
{
this.Logger = logger;
this.Logs = new List<LSP.Diagnostic>();
}
public static LogLevel MapLevel(LSP.DiagnosticSeverity original)
{
switch (original)
{
case LSP.DiagnosticSeverity.Error:
return LogLevel.Error;
case LSP.DiagnosticSeverity.Warning:
return LogLevel.Warning;
case LSP.DiagnosticSeverity.Information:
return LogLevel.Information;
case LSP.DiagnosticSeverity.Hint:
return LogLevel.Debug;
default:
return LogLevel.Trace;
}
}
public bool HasErrors =>
Logs
.Exists(m => m.Severity == LSP.DiagnosticSeverity.Error);
public System.Func<LSP.Diagnostic, string> Format =>
QsCompiler.Diagnostics.Formatting.MsBuildFormat;
public virtual IEnumerable<string> Messages =>
this.Logs.Select(Format);
public IEnumerable<string> Errors =>
Logs
.Where(m => m.Severity == LSP.DiagnosticSeverity.Error)
.Select(Format);
public IEnumerable<string> Warnings =>
Logs
.Where(m => m.Severity == LSP.DiagnosticSeverity.Warning)
.Select(Format);
public IEnumerable<string> ErrorIds =>
Logs
.Where(m => m.Severity == VisualStudio.LanguageServer.Protocol.DiagnosticSeverity.Error)
.Select(m => m.Code);
protected override void Print(LSP.Diagnostic m)
{
Logger?.Log(MapLevel(m.Severity), $"{m.Code}: {m.Message}");
Logs.Add(m);
}
public virtual void LogInfo(string message)
{
Log(new LSP.Diagnostic
{
Severity = LSP.DiagnosticSeverity.Information,
Message = message
});
}
public virtual void LogDebug(string message)
{
Log(new LSP.Diagnostic
{
Severity = LSP.DiagnosticSeverity.Hint,
Message = message
});
}
public virtual void LogWarning(string code, string message)
{
Log(new LSP.Diagnostic
{
Code = code,
Severity = LSP.DiagnosticSeverity.Warning,
Message = message
});
}
public virtual void LogError(string code, string message)
{
Log(new LSP.Diagnostic
{
Code = code,
Severity = LSP.DiagnosticSeverity.Error,
Message = message
});
}
public void Reset()
{
this.Logs.Clear();
}
}
}

126
src/Core/OperationInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,126 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.QsCompiler;
using Microsoft.Quantum.Simulation.Core;
using Newtonsoft.Json;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Represents information about a Q# operation.
/// The operation is extracted from a Roslyn Type, which is expected to be a
/// code-generated class coming from the Q# code generation
/// library.
/// Specifically, it extracts information from the static "Run" method
/// that is auto-generated by the Q# code generation library.
/// </summary>
public class OperationInfo
{
private Lazy<Dictionary<string, string>> _params;
private Lazy<ParameterInfo[]> _roslynParams;
internal OperationInfo(Type roslynType, CallableDeclarationHeader header)
{
this.Header = header ?? throw new ArgumentNullException(nameof(header));
RoslynType = roslynType;
_roslynParams = new Lazy<ParameterInfo[]>(() => RoslynType?.GetMethod("Run").GetParameters().Skip(1).ToArray());
_params = new Lazy<Dictionary<string, string>>(() => RoslynParameters?.ToDictionary(p => p.Name, p => p.ParameterType.Name));
}
public string FullName => Header?.QualifiedName?.ToFullName().WithoutNamespace(Snippets.SNIPPETS_NAMESPACE);
/// <summary>
/// The header containing all callable declaration metadata as
/// serialized in the assembly containing this operation.
/// </summary>
/// <remarks>
/// The data structure for this property is defined by the Q#
/// compiler itself, and is not specific to the IQ# kernel or
/// service.
/// </remarks>
public CallableDeclarationHeader Header { get; }
/// <summary>
/// The underlying compiled .NET Type for this Q# operation
/// </summary>
[JsonIgnore]
public Type RoslynType { get; }
/// <summary>
/// The input parameters for the underlying compiled .NET Type for this Q# operation
/// </summary>
[JsonIgnore]
public ParameterInfo[] RoslynParameters => _roslynParams.Value;
public override string ToString() => FullName;
}
/// <summary>
/// Extension methods for OperationInfo. This allows to keep OperationInfo as a pure
/// data structure but still expose things like RunAsync.
/// </summary>
public static class OperationInfoExtensions
{
public static async Task<object> RunAsync(this OperationInfo op, IOperationFactory qsim, IDictionary<string, string> arguments)
{
if (op?.RoslynType == null) throw new InvalidOperationException($"Operation {op?.FullName} can't be executed.");
var run = op.RoslynType.GetMethod("Run");
var args = op.GetRunArguments(qsim, arguments);
return await (dynamic)run.Invoke(null, args);
}
private static object[] GetRunArguments(this OperationInfo op, IOperationFactory qsim, IDictionary<string, string> arguments)
{
var invalid = new List<string>();
var values = new List<object>();
values.Add(qsim);
foreach (var p in op.RoslynParameters)
{
if (arguments != null && arguments.TryGetValue(p.Name, out var value))
{
try
{
values.Add(ParseInputParameter(p.ParameterType, value?.ToString()));
}
catch (Exception e)
{
invalid.Add($"{p.Name}: {e.Message}");
}
}
else
{
invalid.Add($"{p.Name}: missing.");
}
}
if (invalid.Count > 0)
{
throw new InvalidOperationException($"Received invalid parameters. Please fix and try again:\n {string.Join("\n ", invalid.ToArray())}");
}
return values.ToArray();
}
private static object ParseInputParameter(Type t, string p)
{
if (t == typeof(QVoid))
{
return QVoid.Instance;
}
var value = Newtonsoft.Json.JsonConvert.DeserializeObject(p, t, TupleConverters.Converters);
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Tests.IQsharp" + SigningConstants.PUBLIC_KEY)]
[assembly: InternalsVisibleTo("Microsoft.Quantum.IQSharp.Jupyter" + SigningConstants.PUBLIC_KEY)]

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "We're not following this convention")]

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// List of arguments that are part of the PackageLoaded event.
/// </summary>
public class PackageLoadedEventArgs : EventArgs
{
public PackageLoadedEventArgs(string id, string version, TimeSpan duration)
{
this.PackageId = id;
this.PackageVersion= version;
this.Duration = duration;
}
/// <summary>
/// The nuget Package id.
/// </summary>
public string PackageId { get; }
/// <summary>
/// The nuget Package version.
/// </summary>
public string PackageVersion { get; }
/// <summary>
/// The total time the load package operation took.
/// </summary>
public TimeSpan Duration { get; }
}
/// <summary>
/// This service keeps track of references (assemblies) needed for compilation
/// and exposes them in the different formats, depending on what each compiler need.
/// </summary>
public interface IReferences
{
/// <summary>
/// This event is triggered when a package is successfully loaded.
/// </summary>
event EventHandler<PackageLoadedEventArgs> PackageLoaded;
/// <summary>
/// The plain list of Assemblies to be used as References.
/// </summary>
ImmutableArray<AssemblyInfo> Assemblies { get; }
/// <summary>
/// The compiler metadata information for the currently loaded assemblies.
/// </summary>
CompilerMetadata CompilerMetadata { get; }
/// <summary>
/// The list of Nuget Packages that are installed for compilation and execution.
/// </summary>
IEnumerable<string> Packages { get; }
/// <summary>
/// Adds a nuget package and its corresponding assemblies to the list of references.
/// </summary>
Task AddPackage(string name);
}
}

Просмотреть файл

@ -0,0 +1,442 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Quantum.IQSharp.Common;
using NuGet.Configuration;
using NuGet.Frameworks;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Packaging.Signing;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Resolver;
using NuGet.Versioning;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// This class takes care of managing Nuget packages: it provides support
/// for adding packages by finding all its dependencies and downloading them if necessary.
/// </summary>
public class NugetPackages
{
// The string we use to delimit the version from the package id.
public static readonly string PACKAGE_VERSION_DELIMITER = "::";
// The list of settings for this class. It extends Workspace.Settings so it can get things
// list root and cache folder.
public class Settings : Workspace.Settings
{
public string[] DefaultPackageVersions { get; set; }
}
// The framework used to find packages.
// We only use netcoreapp2.1, as IQSharp is built against this moniker.
public static NuGetFramework NETCOREAPP2_1 = NuGetFramework.ParseFolder("netcoreapp2.1");
// Nuget's logger.
public NuGetLogger Logger { get; }
// List of Packages already installed.
public IEnumerable<PackageIdentity> Items { get; private set; }
// List of Assemblies from current Packages..
public IEnumerable<AssemblyInfo> Assemblies { get; private set; }
// List of Nuget repositories. This is populated from NugetSettings.
// It can't be cached otherwise we can't detect changes to repositores.
public IEnumerable<SourceRepository> Repositories
{
get
{
// global packages (i.e. ~/.nuget/packages)
var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(NugetSettings);
Logger?.LogDebug($"Using nuget global packages cache from: {globalPackagesFolder}");
yield return Repository.CreateSource(Repository.Provider.GetCoreV3(), globalPackagesFolder);
// fallback folders (i.e. /dotnet/sdk/NugetFallbackFolder)
foreach (var folder in SettingsUtility.GetFallbackPackageFolders(NugetSettings))
{
Logger?.LogDebug($"Using nuget fallback feed at: {folder}");
yield return Repository.CreateSource(Repository.Provider.GetCoreV3(), folder);
}
// Other sources as defined in Nuget.config:
foreach(var source in new SourceRepositoryProvider(NugetSettings, Repository.Provider.GetCoreV3()).GetRepositories())
{
Logger?.LogDebug($"Using nuget feed: {source.PackageSource.Name}");
yield return source;
}
}
}
// Nuget's way to find path of local packages
public FindLocalPackagesResource LocalPackagesFinder =>
this.Repositories.First().GetResource<FindLocalPackagesResource>();
// Nuget's global settings.
public ISettings NugetSettings { get; }
// Keeps track of what package version to use for certain packages specified in the packageVersion.json.
// This way we can better control what the correct version of Microsoft.Quantum
// packages to use, since all of them need to be in-sync.
public IReadOnlyDictionary<string, NuGetVersion> DefaultVersions { get; }
public NugetPackages(IOptions<Settings> config, Microsoft.Extensions.Logging.ILogger logger)
{
this.Logger = new NuGetLogger(logger);
this.NugetSettings = NuGet.Configuration.Settings.LoadDefaultSettings(root: config?.Value.Workspace);
this.DefaultVersions = InitDefaultVersions(config?.Value.DefaultPackageVersions);
this.Items = Enumerable.Empty<PackageIdentity>();
this.Assemblies = Enumerable.Empty<AssemblyInfo>();
}
/// <summary>
/// Inits the list of default packages versions from the configuration.
/// Each element on the config array is expected to be a package; all packages are expected to have a version
/// thus the name is checked for package delimiter (::)
/// </summary>
public IReadOnlyDictionary<string, NuGetVersion> InitDefaultVersions(string[] config)
{
var versions = new Dictionary<string, NuGetVersion>(StringComparer.OrdinalIgnoreCase);
if (config != null)
{
foreach (var info in config)
{
var index = info.IndexOf(PACKAGE_VERSION_DELIMITER);
Debug.Assert(index > 0);
if (index > 0)
{
var pkg = ParsePackageId(info).Result;
versions[pkg.Id] = pkg.Version;
}
else
{
Logger.LogWarning($"Invalid package version '{info}'. Expecting package in format 'pkgId::pkgVersion'");
}
}
}
return versions;
}
/// <summary>
/// Given a package name, generates a PackageId.
/// The package name can include the version delimited by double colon (::). If not,
/// it will call GetLatestVersion to get the latest version found across all sources.
/// </summary>
/// <exception cref="System.ArgumentNullException">
/// If <paramref name="package" /> is <c>null</c>.
/// </exception>
public async Task<PackageIdentity> ParsePackageId(string package)
{
package = package?.Trim() ?? throw new ArgumentNullException(nameof(package));
var index = package.IndexOf(PACKAGE_VERSION_DELIMITER);
if (index > 0)
{
var name = package.Substring(0, index);
var version = package.Substring(index + PACKAGE_VERSION_DELIMITER.Length);
return new PackageIdentity(name, NuGetVersion.Parse(version));
}
else
{
return new PackageIdentity(package, await GetLatestVersion(package));
}
}
/// <summary>
/// Adds a new package given the name and version as strings.
/// </summary>
public async Task<PackageIdentity> Add(string package)
{
if (string.IsNullOrWhiteSpace(package))
{
throw new InvalidOperationException("Please provide a name of a package.");
}
var pkgId = await ParsePackageId(package);
await Add(pkgId);
return pkgId;
}
/// <summary>
/// Adds the given package.
/// </summary>
public async Task Add(PackageIdentity pkgId)
{
// Already added:
if (Items.Contains(pkgId)) return;
using (var sourceCacheContext = new SourceCacheContext())
{
var packages = await GetPackageDependencies(pkgId, sourceCacheContext);
await DownloadPackages(sourceCacheContext, packages);
this.Items = Items.Union(new PackageIdentity[] { pkgId }).ToArray();
this.Assemblies = Assemblies.Union(packages.Reverse().SelectMany(GetAssemblies)).ToArray();
}
}
/// <summary>
/// Returns true if the package exists in the GlobalPackages folder.
/// </summary>
public bool IsInstalled(PackageIdentity pkg) => LocalPackagesFinder.Exists(pkg, Logger, CancellationToken.None);
/// <summary>
/// Identifies system packages, i.e., those that should be installed as part of .net.
/// These packages will not be downloaded nor will we try to get their list of assemblies.
/// </summary>
public static bool IsSystemPackage(PackageIdentity pkg) =>
pkg.Id.StartsWith("System", StringComparison.InvariantCultureIgnoreCase) ||
pkg.Id.StartsWith("Microsoft.NET", StringComparison.InvariantCultureIgnoreCase) ||
pkg.Id.StartsWith("NETStandard", StringComparison.InvariantCultureIgnoreCase) ||
pkg.Id.StartsWith("Microsoft.Win32", StringComparison.InvariantCultureIgnoreCase);
/// <summary>
/// Downloads and extracts a package into the GlobalPackages folder.
/// </summary>
public async Task DownloadPackages(SourceCacheContext context, IEnumerable<SourcePackageDependencyInfo> packagesToInstall)
{
foreach (var pkg in packagesToInstall)
{
// Ignore all SDK packages:
if (IsSystemPackage(pkg)) continue;
if (!IsInstalled(pkg))
{
var downloadResource = await pkg.Source.GetResourceAsync<DownloadResource>(CancellationToken.None);
var downloadResult = await downloadResource.GetDownloadResourceResultAsync(
pkg,
new PackageDownloadContext(context),
SettingsUtility.GetGlobalPackagesFolder(NugetSettings),
Logger, CancellationToken.None);
await GlobalPackagesFolderUtility.AddPackageAsync(
source: null,
packageIdentity: pkg,
packageStream: downloadResult.PackageStream,
globalPackagesFolder: LocalPackagesFinder.Root,
clientPolicyContext: ClientPolicyContext.GetClientPolicy(NugetSettings, Logger),
logger: Logger,
parentId: Guid.Empty,
token: CancellationToken.None);
}
}
}
/// <summary>
/// Find the list of netstandard Assemblies (if any) for the given package.
/// Certain System and .NET packages are ignored as the assemblies of these should
/// be automatically included without package references.
/// </summary>
public IEnumerable<AssemblyInfo> GetAssemblies(PackageIdentity pkg)
{
// Ignore all SDK packages:
if (pkg == null || IsSystemPackage(pkg)) return Enumerable.Empty<AssemblyInfo>();
var pkgInfo = LocalPackagesFinder.GetPackage(pkg, Logger, CancellationToken.None);
var packageReader = pkgInfo?.GetReader();
var libs = packageReader?.GetLibItems();
// If package contains no dlls:
if (libs == null)
{
Logger.LogWarning($"Could not find any dll for {pkg}");
return Enumerable.Empty<AssemblyInfo>();
}
var root = Path.GetDirectoryName(pkgInfo.Path);
string[] CheckOnFramework(NuGetFramework framework)
{
var frameworkReducer = new FrameworkReducer();
var nearest = frameworkReducer.GetNearest(framework, libs.Select(x => x.TargetFramework));
if (nearest == null) return new string[0];
var files = libs
.Where(x => x.TargetFramework.Equals(nearest))
.SelectMany(x => x.Items)
.Where(n => n.EndsWith(".dll"))
.Select(p => Path.Combine(root, p));
return files.ToArray();
}
var names = CheckOnFramework(NETCOREAPP2_1);
Assembly LoadAssembly(string path)
{
try
{
return Assembly.LoadFile(path);
}
catch (Exception e)
{
Logger.LogWarning($"Unable to load assembly '{path}' ({e.Message})");
return null;
}
}
return names
.Select(LoadAssembly)
.Select(AssemblyInfo.Create)
.Where(a => a != null);
}
/// <summary>
/// Finds the latest version of the package with the given id.
/// The id must match. It returns null if the package is not found.
/// </summary>
public async Task<NuGetVersion> GetLatestVersion(string package)
{
package = package?.Trim() ?? throw new ArgumentNullException(nameof(package));
NuGetVersion found = null;
if (DefaultVersions.TryGetValue(package, out found))
{
return found;
}
foreach (var repo in this.Repositories)
{
try
{
var feed = await repo.GetResourceAsync<ListResource>();
if (feed == null) continue;
var metadatas = await feed.ListAsync(package, prerelease: false, allVersions: false, includeDelisted: false, log: Logger, token: CancellationToken.None);
if (metadatas == null) continue;
var e = metadatas.GetEnumeratorAsync();
while (await e.MoveNextAsync())
{
if (string.Equals(e.Current.Identity.Id, package, StringComparison.InvariantCultureIgnoreCase) && e.Current.Identity.HasVersion)
{
var current = e.Current.Identity.Version;
if (found == null || found < current)
{
found = current;
}
}
}
}
catch (NuGetProtocolException e)
{
Logger?.LogWarning($"Repository throw exception: {e.Message}");
}
}
return found;
}
/// <summary>
/// Finds all the dependencies of the given package.
/// </summary>
public async Task<IEnumerable<SourcePackageDependencyInfo>> GetPackageDependencies(
PackageIdentity package,
SourceCacheContext context)
{
var all = new HashSet<SourcePackageDependencyInfo>(PackageIdentityComparer.Default);
await FindDependencies(package, context, all);
return ResolveDependencyGraph(package, all);
}
/// Flattens the list of dependency packages to a single list of packages to be installed.
public IEnumerable<SourcePackageDependencyInfo> ResolveDependencyGraph(PackageIdentity pkgId, IEnumerable<SourcePackageDependencyInfo> dependencies)
{
// We used PackageResolver to flatten the dependency graph. This is the process Nuget uses
// when adding a package to a project. It takes:
// - a list of targets, in this case the package we want to add
// - a list of packages already installed, (i.e. the package that used to be defined in the packages.config)
// * in our case, the packages already added to this service
// - a list of available packages (i.e. the list of packages in the nuget sources).
// * in our case, all the dependencies we already found via GetPackageDependencies
// The resolver will then filter out the list such that only one version of each package
// gets installed.
var resolverContext = new PackageResolverContext(
dependencyBehavior: DependencyBehavior.Lowest,
targetIds: new[] { pkgId.Id },
requiredPackageIds: Enumerable.Empty<string>(),
packagesConfig: Items.Select(p => new PackageReference(p, NETCOREAPP2_1, true)),
preferredVersions: Enumerable.Empty<PackageIdentity>(),
availablePackages: dependencies,
packageSources: Repositories.Select(s => s.PackageSource),
log: Logger);
var resolver = new PackageResolver();
return resolver.Resolve(resolverContext, CancellationToken.None)
.Select(p => dependencies.Single(x => PackageIdentityComparer.Default.Equals(x, p)));
}
/// <summary>
/// Recursively finds all the dependencies of the given package and returns in the
/// dependencies.
/// </summary>
internal async Task FindDependencies(
PackageIdentity package,
SourceCacheContext context,
ISet<SourcePackageDependencyInfo> dependencies)
{
if (dependencies.Contains(package)) return;
foreach (var repo in this.Repositories)
{
try
{
var dependencyInfoResource = await repo.GetResourceAsync<DependencyInfoResource>();
if (dependencyInfoResource == null) continue;
var dependencyInfo = await dependencyInfoResource.ResolvePackage(package, NETCOREAPP2_1, context, this.Logger, CancellationToken.None);
if (dependencyInfo == null) continue;
dependencies.Add(dependencyInfo);
foreach (var dependency in dependencyInfo.Dependencies)
{
await FindDependencies(
new PackageIdentity(dependency.Id, dependency.VersionRange.MinVersion),
context, dependencies);
}
// dependencies found, no need to look into next repo
break;
}
catch (NuGetProtocolException) { }
}
}
/// <summary>
/// Helper method that creates a new instance with default dependencies.
/// Used mainly for testing.
/// </summary>
internal static NugetPackages Create()
{
var logger = new LoggerFactory().CreateLogger<NugetPackages>();
return new NugetPackages(null, logger);
}
}
}

Просмотреть файл

@ -0,0 +1,121 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Quantum.IQSharp.Common;
using Newtonsoft.Json.Linq;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Default implementation of IReferences.
/// This service keeps track of references (assemblies) needed for compilation
/// and exposes them in the different formats, depending on what each
/// compiler needs.
/// </summary>
public class References : IReferences
{
/// <summary>
/// The list of assemblies that are automatically included for compilation. Namely:
/// * Quantum.Core
/// * Quantum.Intrinsic
/// * Quantum.Standard
/// </summary>
public static readonly AssemblyInfo[] QUANTUM_CORE_ASSEMBLIES =
{
new AssemblyInfo(typeof(Simulation.Core.Operation<,>).Assembly),
new AssemblyInfo(typeof(Intrinsic.X).Assembly)
};
public static readonly string[] BUILT_IN_PACKAGES =
{
"Microsoft.Quantum.Standard"
};
/// <summary>
/// Create a new References list populated with the list of DEFAULT_ASSEMBLIES
/// </summary>
public References(IOptions<NugetPackages.Settings> options, ILogger<References> logger)
{
Assemblies = QUANTUM_CORE_ASSEMBLIES.ToImmutableArray();
Nugets = new NugetPackages(options, logger);
foreach (var pkg in BUILT_IN_PACKAGES)
{
AddPackage(pkg).Wait();
}
AssemblyLoadContext.Default.Resolving += Resolve;
Reset();
}
/// Manages nuget packages.
internal NugetPackages Nugets { get; }
private Lazy<CompilerMetadata> _metadata;
public event EventHandler<PackageLoadedEventArgs> PackageLoaded;
/// <summary>
/// The plain list of Assemblies to be used as References.
/// </summary>
public ImmutableArray<AssemblyInfo> Assemblies { get; private set; }
public CompilerMetadata CompilerMetadata => _metadata.Value;
/// <summary>
/// The list of Nuget Packages that are available for compilation and execution.
/// </summary>
public virtual IEnumerable<string> Packages =>
Nugets?
.Items
.Select(p => $"{p.Id}::{p.Version}");
/// <summary>
/// Adds the libraries from the given nuget package to the list of assemblies.
/// If version is not provided. It automatically picks up the latest version.
/// </summary>
public async Task AddPackage(string name)
{
var duration = Stopwatch.StartNew();
if (Nugets == null)
{
throw new InvalidOperationException("Packages can be only added to the global references collection");
}
var pkg = await Nugets.Add(name);
Assemblies = Assemblies.Union(Nugets.Assemblies).ToImmutableArray();
Reset();
duration.Stop();
PackageLoaded?.Invoke(this, new PackageLoadedEventArgs(pkg.Id, pkg.Version.ToNormalizedString(), duration.Elapsed));
}
private void Reset()
{
_metadata = new Lazy<CompilerMetadata>(() => new CompilerMetadata(this.Assemblies));
}
/// <summary>
/// Because the assemblies are loaded into memory, we need to provide this method to the AssemblyLoadContext
/// such that the Workspace assembly or this assembly is correctly resolved when it is executed for simulation.
/// </summary>
public Assembly Resolve(AssemblyLoadContext context, AssemblyName name) =>
Assemblies.FirstOrDefault(a => a.Assembly.FullName == name.FullName)?.Assembly;
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
public interface IOperationResolver
{
OperationInfo Resolve(string input);
}
}

Просмотреть файл

@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Resolves Q# symbols into Jupyter Core symbols to be used for
/// documentation requests.
/// </summary>
public class OperationResolver : IOperationResolver
{
private readonly ISnippets snippets;
private readonly IWorkspace workspace;
private readonly IReferences references;
/// <summary>
/// Constructs a new resolver that looks for symbols in a given
/// collection of snippets.
/// </summary>
/// <param name="snippets">
/// The collection of snippets to be used when resolving symbols.
/// </param>
public OperationResolver(ISnippets snippets, IWorkspace workspace, IReferences references)
{
this.snippets = snippets;
this.workspace = workspace;
this.references = references;
}
/// <summary>
/// Creates a SymbolResolver from a Snippets implementation. Only used for testing.
/// </summary>
internal OperationResolver(Snippets snippets)
{
this.snippets = snippets;
this.workspace = snippets.Workspace;
this.references = snippets.GlobalReferences;
}
/// <summary>
/// Enumerates over all assemblies that should be searched
/// when resolving symbols.
/// </summary>
private IEnumerable<AssemblyInfo> RelevantAssemblies()
{
if (snippets.AssemblyInfo != null) yield return snippets.AssemblyInfo;
if (workspace.AssemblyInfo != null) yield return workspace.AssemblyInfo;
foreach (var asm in references.Assemblies)
{
yield return asm;
}
}
/// <summary>
/// Resolves a given symbol name into a Q# symbol
/// by searching through all relevant assemblies.
/// </summary>
/// <returns>
/// The symbol instance if resolution is successful, otherwise <c>null</c>.
/// </returns>
/// <remarks>
/// If the symbol to be resolved contains a dot,
/// it is treated as a fully qualified name, and will
/// only be resolved to a symbol whose name matches exactly.
/// Symbol names without a dot are resolved to the first symbol
/// whose base name matches the given name.
/// </remarks>
public OperationInfo Resolve(string name)
{
var isQualified = name.Contains('.');
foreach (var operation in RelevantAssemblies().SelectMany(asm => asm.Operations))
{
if (name == (isQualified ? operation.FullName : operation.Header.QualifiedName.Name.Value))
{
return operation;
}
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// List of arguments that are part of the Compile Snippet event.
/// </summary>
public class SnippetCompiledEventArgs : EventArgs
{
public SnippetCompiledEventArgs(string status, string[] errors, TimeSpan duration)
{
this.Status = status;
this.Errors = errors;
this.Duration = duration;
}
/// <summary>
/// The workspace status. Can be "success" or "error"
/// </summary>
public string Status { get; }
/// <summary>
/// The list of error ids reported by the Q# parser (if any).
/// </summary>
public string[] Errors { get; }
/// <summary>
/// The total time the reload operation took.
/// </summary>
public TimeSpan Duration { get; }
}
/// <summary>
/// Snippets represent pieces of Q# code provided by the user.
/// These snippets are efemeral thus not part of the Workspace.
/// This service keeps track of the Snippets provided by the user and
/// compiles all of them into a single Assembly that can then be used for execution.
/// </summary>
public interface ISnippets
{
/// <summary>
/// This event is triggered when a Snippet finishes compilation.
/// </summary>
event EventHandler<SnippetCompiledEventArgs> SnippetCompiled;
/// <summary>
/// The information of the assembly compiled from all the given snippets
/// </summary>
AssemblyInfo AssemblyInfo { get; }
/// <summary>
/// Adds or updates a snippet of code. If successful, this updates the AssemblyInfo
/// with the new operations found in the Snippet and returns a new Snippet
/// populated with the results of the compilation.
/// </summary>
Snippet Compile(string code);
/// <summary>
/// The list of operations found in all snippets compiled successfully so far.
/// </summary>
IEnumerable<OperationInfo> Operations { get; }
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.IO;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.IQSharp.Common;
using Newtonsoft.Json;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// A Snippet represents a piece of Q# code provided by the user.
/// These snippets are ephemeral thus not part of the environment.
/// Each Snippet represents a single entry from the user.
/// During execution, a user may provide multiple Snippets.
/// </summary>
public class Snippet
{
/// <summary>
/// An id of the snippet. This gives users control on whether they are updating
/// or creating a new Snippet.
/// </summary>
public string id { get; set; }
/// <summary>
/// The actual source code from the user.
/// </summary>
public string code { get; set; }
/// <summary>
/// Any compilation warnings trigger for this Snippet.
/// </summary>
public string[] warnings { get; set; }
/// <summary>
/// The Q# compiled version of the operations.
/// </summary>
[JsonIgnore]
public QsNamespaceElement[] Elements { get; set; }
/// <summary>
/// The compiler needs an actual URI for each piece of Q# code
// that it is going to compile.
/// </summary>
[JsonIgnore]
public Uri Uri => new Uri(Path.GetFullPath(Path.Combine("/", $"snippet:{id}")));
}
}

Просмотреть файл

@ -0,0 +1,184 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.Logging;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// Default implementation of ISnippets.
/// Snippets represent pieces of Q# code provided by the user.
/// These snippets are efemeral thus not part of the Workspace.
/// This service keeps track of the Snippets provided by the user and
/// compiles all of them into a single Assembly that can then be used for execution.
/// </summary>
public class Snippets : ISnippets
{
/// <summary>
/// Namespace that all Snippets gets compiled into.
/// </summary>
public static readonly string SNIPPETS_NAMESPACE = "SNIPPET";
public Snippets(ICompilerService compiler, IWorkspace workspace, IReferences references, ILogger<Snippets> logger)
{
Compiler = compiler;
Workspace = workspace;
GlobalReferences = references;
Logger = logger;
AssemblyInfo = new AssemblyInfo(null);
Items = new Snippet[0];
AssemblyLoadContext.Default.Resolving += Resolve;
}
/// <summary>
/// This event is triggered when a Snippet finishes compilation.
/// </summary>
public event EventHandler<SnippetCompiledEventArgs> SnippetCompiled;
/// <summary>
/// The information of the assembly compiled from all the given snippets
/// </summary>
public AssemblyInfo AssemblyInfo { get; set; }
/// <summary>
/// The Workspace these Snippets depend on. Snippets may call operations
/// defined in this Workspace.
/// </summary>
internal IWorkspace Workspace { get; }
/// <summary>
/// The assembly references that should be provided to the compiler when
/// building all snippets.
/// </summary>
internal IReferences GlobalReferences { get; }
/// <summary>
/// The service that takes care of compiling code.
/// </summary>
internal ICompilerService Compiler { get; }
/// <summary>
/// Logger instance used for .net core logging.
/// </summary>
internal ILogger Logger { get; }
/// <summary>
/// The list of currently available snippets.
/// </summary>
internal IEnumerable<Snippet> Items { get; set; }
/// <summary>
/// The list of Q# operations available across all snippets.
/// </summary>
public IEnumerable<OperationInfo> Operations =>
(Workspace == null || Workspace.HasErrors)
? AssemblyInfo?.Operations
: AssemblyInfo?.Operations
.Concat(
Workspace
?.AssemblyInfo
?.Operations
);
/// <summary>
/// Compiles the given code.
/// If the operations defined in this code are already defined
/// in existing Snippets, those Snippets are skipped.
/// If successful, this updates the AssemblyInfo
/// with the new operations found in the Snippet.
/// If errors are found during compilation, a `CompilationErrorsException` is triggered
/// with the list of errors found.
/// If successful, the list of snippets is updated to include those that were part of the
/// compilation and it will return a new Snippet with the warnings and Q# elements
/// reported by the compiler.
/// </summary>
public Snippet Compile(string code)
{
if (string.IsNullOrWhiteSpace(code)) throw new ArgumentNullException(nameof(code));
var duration = Stopwatch.StartNew();
var logger = new QSharpLogger(Logger);
try
{
var snippets = SelectSnippetsToCompile(code).ToArray();
var references = Workspace.HasErrors
? GlobalReferences.CompilerMetadata
: GlobalReferences?.CompilerMetadata.WithAssemblies(Workspace.AssemblyInfo);
var assembly = Compiler.BuildSnippets(snippets, references, logger, Path.Combine(Workspace.CacheFolder, "__snippets__.dll"));
if (logger.HasErrors)
{
throw new CompilationErrorsException(logger.Errors.ToArray());
}
// populate the original snippet with the results of the compilation:
Snippet populate(Snippet s) =>
new Snippet()
{
id = string.IsNullOrWhiteSpace(s.id) ? System.Guid.NewGuid().ToString() : s.id,
code = s.code,
warnings = logger.Logs.Where(m => m.Source == s.Uri.AbsolutePath).Select(logger.Format).ToArray(),
Elements = assembly?.SyntaxTree?
.SelectMany(ns => ns.Elements)
.Where(c => c.SourceFile() == s.Uri.AbsolutePath)
.ToArray()
};
AssemblyInfo = assembly;
Items = snippets.Select(populate).ToArray();
return Items.Last();
}
finally
{
duration.Stop();
var status = logger.HasErrors ? "error" : "ok";
var errorIds = logger.ErrorIds .ToArray();
SnippetCompiled?.Invoke(this, new SnippetCompiledEventArgs(status, errorIds, duration.Elapsed));
}
}
/// <summary>
/// Selects the list of snippets to compile.
/// Basically it consumes all current Snippets except those related to `newSnippet`
/// - either because they have the same id, or because they previously defined an operation
/// which is in the new Snippet - and replaces them with `newSnippet` itself.
/// </summary>
private IEnumerable<Snippet> SelectSnippetsToCompile(string code)
{
var ops = Compiler.IdentifyElements(code).Select(Extensions.ToFullName).ToArray();
var snippetsWithNoOverlap = Items.Where(s => !s.Elements.Select(Extensions.ToFullName).Intersect(ops).Any());
return snippetsWithNoOverlap.Append(new Snippet { code = code });
}
/// <summary>
/// Because the assemblies are loaded into memory, we need to provide this method to the AssemblyLoadContext
/// such that the Workspace assembly or this assembly is correctly resolved when it is executed for simulation.
/// </summary>
public Assembly Resolve(AssemblyLoadContext context, AssemblyName name)
{
if (name.Name == Path.GetFileNameWithoutExtension(this.AssemblyInfo?.Location))
{
return this.AssemblyInfo.Assembly;
}
else if (name.Name == Path.GetFileNameWithoutExtension(this.Workspace?.AssemblyInfo?.Location))
{
return this.Workspace.AssemblyInfo.Assembly;
}
return null;
}
}
}

150
src/Core/TupleConversion.cs Normal file
Просмотреть файл

@ -0,0 +1,150 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Quantum.Simulation.Core;
using System.Diagnostics;
using System.Text;
using System.IO;
namespace Microsoft.Quantum.IQSharp
{
public static class TupleConverters
{
private static readonly ImmutableList<JsonConverter> converters;
public static JsonConverter[] Converters => converters.ToArray();
static TupleConverters()
{
converters = new JsonConverter[] {
new QTupleConverter(),
new QVoidConverter(),
new UDTConverter()
}.ToImmutableList();
}
/// <summary>
/// A helper method to read a json object and return it as a dictionary.
/// Only the immediate elements of the object are used as keys. Their values
/// are returned as json objects themselves.
/// </summary>
/// <returns></returns>
public static Dictionary<string, string> JsonToDict(string json)
{
var result = new Dictionary<string, string>();
var args = JObject.Parse(json);
foreach (var a in args)
{
result.Add(a.Key, a.Value?.ToString(Formatting.None));
}
return result;
}
}
public class UDTConverter : JsonConverter
{
public override bool CanRead => true;
public override bool CanWrite => true;
public override bool CanConvert(Type objectType) =>
objectType.IsSubclassOfGenericType(typeof(UDTBase<>));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Create an instance of the base Data type and populate it with the jObject:
var data = Activator.CreateInstance(objectType.GetProperty("Data").PropertyType);
serializer.Populate(reader, data);
return Activator.CreateInstance(objectType, data);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objectType = value.GetType();
var dataType = objectType.GetProperty("Data").PropertyType;
var tempWriter = new StringWriter();
serializer.Serialize(tempWriter, objectType.GetProperty("Data").GetValue(value), dataType);
var token = JToken.Parse(tempWriter.ToString());
token["@type"] = objectType.FullName;
token.WriteTo(writer);
}
}
public class QTupleConverter : JsonConverter
{
public override bool CanRead => false;
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(ValueTuple)) return true;
// If we've survived, we either have a nongeneric type which isn't
// a value tuple, or we have a generic value tuple.
if (!objectType.IsGenericType) return false;
// Now we can compare the generic type to each possible pattern for
// value tuples.
var genericType = objectType.GetGenericTypeDefinition();
return genericType == typeof(ValueTuple<>)
|| genericType == typeof(ValueTuple<,>)
|| genericType == typeof(ValueTuple<,,>)
|| genericType == typeof(ValueTuple<,,,>)
|| genericType == typeof(ValueTuple<,,,,>)
|| genericType == typeof(ValueTuple<,,,,,>)
|| genericType == typeof(ValueTuple<,,,,,,>)
|| genericType == typeof(ValueTuple<,,,,,,,>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var type = value.GetType();
var nItems = type.GenericTypeArguments.Length;
var tokenData = new Dictionary<string, object>
{
["@type"] = "@tuple"
};
foreach (var idx in Enumerable.Range(0, nItems))
{
var field = type.GetField($"Item{idx + 1}");
Debug.Assert(field != null, $"Failed trying to look at field Item{idx + 1} of a value tuple with {nItems} type arguments, {type.FullName}.");
tokenData[$"Item{idx + 1}"] = field.GetValue(value);
}
// See https://github.com/JamesNK/Newtonsoft.Json/issues/386#issuecomment-421161191
// for why this works to pass through.
var token = JToken.FromObject(tokenData, serializer);
token.WriteTo(writer);
}
}
public class QVoidConverter : JsonConverter<QVoid>
{
public override QVoid ReadJson(JsonReader reader, Type objectType, QVoid existingValue, bool hasExistingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, QVoid value, JsonSerializer serializer)
{
var token = JToken.FromObject(new Dictionary<string, object>
{
["@type"] = "tuple"
});
token.WriteTo(writer);
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// List of arguments that are part of the Reloaded event.
/// </summary>
public class ReloadedEventArgs : EventArgs
{
public ReloadedEventArgs(string workspace, string status, int filecount, string[] errors, TimeSpan duration)
{
this.Workspace = workspace;
this.Status = status;
this.FileCount = filecount;
this.Errors = errors;
this.Duration = duration;
}
/// <summary>
/// The name of IQ#'s workspace folder
/// </summary>
public string Workspace { get; }
/// <summary>
/// The workspace status. Can be "success" or "error"
/// </summary>
public string Status { get; }
/// <summary>
/// The number of files used for compilation.
/// </summary>
public int FileCount { get; }
/// <summary>
/// The list of error ids reported by the Q# parser (if any).
/// </summary>
public string[] Errors { get; }
/// <summary>
/// The total time the reload operation took.
/// </summary>
public TimeSpan Duration { get; }
}
/// <summary>
/// A Workspace represents a folder in the host with .qs files
/// that are compiled into an Assembly.
/// </summary>
public interface IWorkspace
{
/// <summary>
/// This event is triggered when ever the workspace is reloaded.
/// </summary>
event EventHandler<ReloadedEventArgs> Reloaded;
/// <summary>
/// The root folder.
/// </summary>
string Root { get; }
/// <summary>
/// The folder where the assembly is permanently saved for cache.
/// </summary>
string CacheFolder { get; }
/// <summary>
/// Information of the assembly built from this Workspace.
/// </summary>
AssemblyInfo AssemblyInfo { get; }
/// <summary>
/// The compilation errors, if any.
/// </summary>
IEnumerable<string> ErrorMessages { get; }
/// <summary>
/// If any of the files in the workspace had any compilation errors.
/// </summary>
bool HasErrors { get; }
/// <summary>
/// Triggers the workspace to be reloaded from disk.
/// </summary>
void Reload();
}
}

Просмотреть файл

@ -0,0 +1,252 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp
{
/// <summary>
/// A Workspace represents a folder in the host with .qs files
/// that are compiled into an Assembly.
/// </summary>
public class Workspace : IWorkspace
{
/// <summary>
/// Settings that can be configured via command line or parameters.
/// </summary>
public class Settings
{
private string _workspace;
private string _cacheFolder;
/// <summary>
/// The Workspace's root folder
/// </summary>
public string Workspace
{
get => _workspace ?? Directory.GetCurrentDirectory();
set { _workspace = value; }
}
/// <summary>
/// The folder where the assembly is permanently saved for cache.
/// </summary>
public string CacheFolder
{
get => _cacheFolder ?? Path.Combine(Workspace, "obj");
set { _cacheFolder = value; }
}
public bool MonitorWorkspace { get; set; }
}
// We use this to keep track of file changes in the workspace and trigger a reload.
private FileSystemWatcher Watcher;
/// <summary>
/// This event is triggered when ever the workspace is reloaded.
/// </summary>
public event EventHandler<ReloadedEventArgs> Reloaded;
/// <summary>
/// Logger instance used for .net core logging.
/// </summary>
public ILogger Logger { get; }
/// <summary>
/// All the references used to compile the Assembly of this workspace.
/// </summary>
public IReferences GlobalReferences { get; }
/// <summary>
/// The service that takes care of compiling code.
/// </summary>
public ICompilerService Compiler { get; }
/// <summary>
/// The root folder.
/// </summary>
public string Root { get; set; }
/// <summary>
/// Information about the assembly built from this Workspace.
/// </summary>
public AssemblyInfo AssemblyInfo { get; set; }
/// <summary>
/// The compilation errors, if any.
/// </summary>
public IEnumerable<string> ErrorMessages { get; set; }
/// <summary>
/// If any of the files in the workspace had any compilation errors.
/// </summary>
public bool HasErrors => ErrorMessages == null || ErrorMessages.Any();
/// <summary>
/// The folder where the assembly is permanently saved for cache.
/// </summary>
public string CacheFolder { get; set; }
/// <summary>
/// The full qualified file name of the assembly built from this Workspace
/// </summary>
public string CacheDll => Path.Combine(CacheFolder, "__ws__.dll");
/// <summary>
/// Main constructor that accepts ILogger and IReferences as dependencies.
/// </summary>
/// <param name="logger">Used to log messages to the console.</param>
/// <param name="references">List of references to use to compile the workspace.</param>
public Workspace(IOptions<Settings> config, ICompilerService compiler, IReferences references, ILogger<Workspace> logger, IOptions<ClientInformation> clientInfo)
{
Compiler = compiler;
GlobalReferences = references;
Logger = logger;
Root = config?.Value.Workspace;
CacheFolder = config?.Value.CacheFolder;
var monitor = config?.Value.MonitorWorkspace == true;
logger?.LogInformation($"Starting IQ# Workspace:\n----------------\nRoot: {Root}\nCache folder:{CacheFolder}\nMonitoring changes: {monitor}\nUser agent: {clientInfo?.Value?.UserAgent ?? "<unknown>"}\nHosting environment: {clientInfo?.Value?.HostingEnvironment ?? "<unknown>"}\n----------------");
if (!LoadFromCache())
{
Reload();
}
if (monitor)
{
StartFileWatching();
}
}
/// <summary>
/// We monitor changes on .qs files and reload the Workspace on any events;
/// </summary>
private void StartFileWatching()
{
// Create a new FileSystemWatcher and set its properties.
Watcher = new FileSystemWatcher(Root, "*.qs");
Watcher.IncludeSubdirectories = true;
Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
// Add event handlers.
Watcher.Changed += new FileSystemEventHandler(OnFilesChanged);
Watcher.Created += new FileSystemEventHandler(OnFilesChanged);
Watcher.Deleted += new FileSystemEventHandler(OnFilesChanged);
Watcher.Renamed += new RenamedEventHandler(OnFilesRenamed);
// Begin watching.
Watcher.EnableRaisingEvents = true;
}
private void OnFilesChanged(object source, FileSystemEventArgs e) => Reload();
private void OnFilesRenamed(object source, RenamedEventArgs e) => Reload();
/// <summary>
/// Tries to load the Workspace's information from cache.
/// Returns true on success, false if no cache information is available of the cache is not fresh.
/// </summary>
private bool LoadFromCache()
{
var dir = CacheFolder;
if (!Directory.Exists(dir))
{
Logger?.LogDebug($"Creating cache folder {CacheFolder}.");
Directory.CreateDirectory(dir);
}
if (IsCacheFresh())
{
Logger?.LogDebug($"Loading workspace from cache assembly: {CacheDll}.");
var data = File.ReadAllBytes(CacheDll);
var assm = System.Reflection.Assembly.Load(data);
AssemblyInfo = new AssemblyInfo(assm, CacheDll, null);
ErrorMessages = new string[0];
return true;
}
return false;
}
/// <summary>
/// Compares the timestamp of the cache.dll with the timestamp of each of the .qs files
/// and returns false if any of the .qs files is more recent.
/// </summary>
private bool IsCacheFresh()
{
if (!File.Exists(CacheDll)) return false;
var last = File.GetLastWriteTime(CacheDll);
foreach (var f in Directory.EnumerateFiles(Root, "*.qs", SearchOption.AllDirectories))
{
if (File.GetLastWriteTime(f) > last)
{
Logger?.LogDebug($"Cache {CacheDll} busted by {f}.");
return false;
}
}
return true;
}
/// <summary>
/// Reloads the workspace from disk.
/// </summary>
public void Reload()
{
var duration = Stopwatch.StartNew();
var files = new string[0];
var errorIds = new string[0];
try
{
Logger?.LogInformation($"Reloading workspace at {Root}.");
// Create a new logger for this compilation:
var logger = new QSharpLogger(Logger);
if (File.Exists(CacheDll)) { File.Delete(CacheDll); }
files = Directory.EnumerateFiles(Root, "*.qs", SearchOption.AllDirectories).ToArray();
if (files.Length > 0)
{
Logger?.LogDebug($"{files.Length} found in workspace. Compiling.");
AssemblyInfo = Compiler.BuildFiles(files, GlobalReferences.CompilerMetadata, logger, CacheDll);
ErrorMessages = logger.Errors.ToArray();
errorIds = logger.ErrorIds.ToArray();
}
else
{
Logger?.LogDebug($"No files found in Workspace. Using empty workspace.");
AssemblyInfo = new AssemblyInfo(null, null, null);
ErrorMessages = new string[0];
}
}
finally
{
duration.Stop();
var status = this.HasErrors ? "error" : "ok";
Logger?.LogInformation($"Reloading complete ({status}).");
Reloaded?.Invoke(this, new ReloadedEventArgs(Root, status, files.Length, errorIds, duration.Elapsed));
}
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Jupyter.Core;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// This is a Jupyter Core IChannel that wraps an existing IChannel and
/// adds NewLine symbols (\\n)
/// to every message that gets logged to Stdout and Stderror.
/// </summary>
public class ChannelWithNewLines : IChannel
{
public IChannel BaseChannel { get; }
public ChannelWithNewLines(IChannel original)
{
BaseChannel = original;
}
public static string Format(string msg) => $"{msg}\n";
public void Stdout(string message) => BaseChannel?.Stdout(Format(message));
public void Stderr(string message) => BaseChannel?.Stderr(Format(message));
public void Display(object displayable) => BaseChannel?.Display(displayable);
}
}

28
src/Jupyter/Extensions.cs Normal file
Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public static class Extensions
{
/// <summary>
/// Creates a wrapper of an IChannel that adds new lines to every message
/// sent to stdout and stderr
/// </summary>
public static ChannelWithNewLines WithNewLines(this IChannel original) =>
(original is ChannelWithNewLines ch) ? ch : new ChannelWithNewLines(original);
public static void AddIQSharpKernel(this IServiceCollection services)
{
services.AddSingleton<ISymbolResolver, Jupyter.SymbolResolver>();
services.AddSingleton<IExecutionEngine, Jupyter.IQSharpEngine>();
}
}
}

Просмотреть файл

@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// The IQsharpEngine, used to expose Q# as a Jupyter kernel.
/// </summary>
public class IQSharpEngine : BaseEngine
{
/// <summary>
/// The main constructor. It expects an `ISnippets` instance that takes care
/// of compiling and keeping track of the code Snippets provided by users.
/// </summary>
public IQSharpEngine(
IShellServer shell,
IOptions<KernelContext> context,
ILogger<IQSharpEngine> logger,
IServiceProvider services
) : base(shell, context, logger)
{
this.Snippets = services.GetService<ISnippets>();
this.SymbolsResolver = services.GetService<ISymbolResolver>();
this.MagicResolver = new MagicSymbolResolver(services, logger);
RegisterDisplayEncoder(new IQSharpSymbolToHtmlResultEncoder());
RegisterDisplayEncoder(new IQSharpSymbolToTextResultEncoder());
RegisterJsonEncoder(TupleConverters.Converters);
RegisterSymbolResolver(this.SymbolsResolver);
RegisterSymbolResolver(this.MagicResolver);
}
internal ISnippets Snippets { get; }
internal ISymbolResolver SymbolsResolver { get; }
internal ISymbolResolver MagicResolver { get; }
/// <summary>
/// This is the method used to execute Jupyter "normal" cells. In this case, a normal
/// cell is expected to have a Q# snippet, which gets compiled and we return the name of
/// the operations found. These operations are then available for simulation and estimate.
/// </summary>
public override ExecutionResult ExecuteMundane(string input, IChannel channel)
{
channel = channel.WithNewLines();
try
{
var code = Snippets.Compile(input);
foreach(var m in code.warnings) { channel.Stdout(m); }
// Gets the names of all the operations found for this snippet
var opsNames =
code.Elements?
.Where(e => e.IsQsCallable)
.Select(e => e.ToFullName().WithoutNamespace(IQSharp.Snippets.SNIPPETS_NAMESPACE))
.OrderBy(o => o)
.ToArray();
return opsNames.ToExecutionResult();
}
catch (CompilationErrorsException c)
{
foreach (var m in c.Errors) channel.Stderr(m);
return ExecuteStatus.Error.ToExecutionResult();
}
catch (Exception e)
{
channel.Stderr(e.Message);
return ExecuteStatus.Error.ToExecutionResult();
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>Microsoft.Quantum.IQSharp.Jupyter</RootNamespace>
<AssemblyName>Microsoft.Quantum.IQSharp.Jupyter</AssemblyName>
</PropertyGroup>
<ItemGroup>
<None Remove="res\kernel.js" />
<None Remove="res\logo-64x64.png" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\build\DelaySign.cs" Link="Properties\DelaySign.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="res\kernel.js" />
<EmbeddedResource Include="res\logo-64x64.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Jupyter.Core" Version="1.1.14623" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Jupyter.Core;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// These are the list of properties for the Q# Jupyter Kernel.
/// </summary>
public static class Constants
{
public static readonly KernelProperties IQSharpKernelProperties = new KernelProperties
{
FriendlyName = "Q#",
KernelName = "iqsharp",
KernelVersion = typeof(IQSharpEngine).Assembly.GetName().Version.ToString(),
DisplayName = "Q#",
LanguageName = "qsharp",
LanguageVersion = "0.4",
LanguageMimeType = "text/x-qsharp",
LanguageFileExtension = ".qs",
Description = "A kernel for the Q# language."
};
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public abstract class AbstractMagic : MagicSymbol
{
public AbstractMagic(string keyword, Documentation docs)
{
this.Name = $"%{keyword}";
this.Documentation = docs;
this.Kind = SymbolKind.Magic;
this.Execute = SafeExecute(this.Run);
}
public Func<string, IChannel, ExecutionResult> SafeExecute(Func<string, IChannel, ExecutionResult> magic) =>
(input, channel) =>
{
channel = channel.WithNewLines();
try
{
return magic(input, channel);
}
catch (InvalidWorkspaceException ws)
{
foreach (var m in ws.Errors) channel.Stderr(m);
return ExecuteStatus.Error.ToExecutionResult();
}
catch (AggregateException agg)
{
foreach (var e in agg.InnerExceptions) channel.Stderr(e?.Message);
return ExecuteStatus.Error.ToExecutionResult();
}
catch (Exception e)
{
channel.Stderr(e.Message);
return ExecuteStatus.Error.ToExecutionResult();
}
};
public static (string, Dictionary<string, string>) ParseInput(string input)
{
if (input == null) return (string.Empty, new Dictionary<string, string> { });
var BLANK_SPACE = new char[1] { ' ' };
var inputParts = input.Split(BLANK_SPACE, 2, StringSplitOptions.RemoveEmptyEntries);
var name = inputParts.Length > 0 ? inputParts[0] : string.Empty;
var args = inputParts.Length > 1
? TupleConverters.JsonToDict(inputParts[1])
: new Dictionary<string, string> { };
return (name, args);
}
public abstract ExecutionResult Run(string input, IChannel channel);
}
}

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading.Tasks;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
using Microsoft.Quantum.Simulation.Simulators;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public class EstimateMagic : AbstractMagic
{
public EstimateMagic(ISymbolResolver resolver) : base(
"estimate",
new Documentation {
Summary = "Runs a given function or operation on the QuantumSimulator target machine"
})
{
this.SymbolResolver = resolver;
}
public ISymbolResolver SymbolResolver { get; }
public override ExecutionResult Run(string input, IChannel channel) =>
RunAsync(input, channel).Result;
public async Task<ExecutionResult> RunAsync(string input, IChannel channel)
{
var (name, args) = ParseInput(input);
var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol;
if (symbol == null) throw new InvalidOperationException($"Invalid operation name: {name}");
var qsim = new ResourcesEstimator();
qsim.DisableLogToConsole();
await symbol.Operation.RunAsync(qsim, args);
return qsim.AsDictionary().ToExecutionResult();
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Jupyter;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public class PackageMagic : AbstractMagic
{
public PackageMagic(IReferences references) : base(
"package",
new Documentation {
Summary = "Provides the ability to load a Nuget package. The package must be available on the list of nuget sources, typically this includes nuget.org"
})
{
this.References = references;
}
public IReferences References { get; }
public override ExecutionResult Run(string input, IChannel channel) =>
RunAsync(input, channel).Result;
public async Task<ExecutionResult> RunAsync(string input, IChannel channel)
{
var (name, _) = ParseInput(input);
if (!string.IsNullOrWhiteSpace(name))
{
await References.AddPackage(name);
}
return References.Packages.ToArray().ToExecutionResult();
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading.Tasks;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
using Microsoft.Quantum.Simulation.Simulators;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public class SimulateMagic : AbstractMagic
{
public SimulateMagic(ISymbolResolver resolver) : base(
"simulate",
new Documentation {
Summary = "Runs a given function or operation on the QuantumSimulator target machine"
})
{
this.SymbolResolver = resolver;
}
public ISymbolResolver SymbolResolver { get; }
public override ExecutionResult Run(string input, IChannel channel) =>
RunAsync(input, channel).Result;
public async Task<ExecutionResult> RunAsync(string input, IChannel channel)
{
var (name, args) = ParseInput(input);
var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol;
if (symbol == null) throw new InvalidOperationException($"Invalid operation name: {name}");
using (var qsim = new QuantumSimulator())
{
qsim.DisableLogToConsole();
qsim.OnLog += channel.Stdout;
var value = await symbol.Operation.RunAsync(qsim, args);
return value.ToExecutionResult();
}
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading.Tasks;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
using Microsoft.Quantum.Simulation.Simulators;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// Runs a given function or operation on the ToffoliSimulator target machine.
/// </summary>
public class ToffoliMagic : AbstractMagic
{
/// <summary>
/// Default constructor.
/// </summary>
public ToffoliMagic(ISymbolResolver resolver) : base(
"toffoli",
new Documentation {
Summary = "Runs a given function or operation on the ToffoliSimulator simulator target machine"
})
{
this.SymbolResolver = resolver;
}
/// <summary>
/// ISumbolResolver used to find the function/operation to simulate.
/// </summary>
public ISymbolResolver SymbolResolver { get; }
public override ExecutionResult Run(string input, IChannel channel) =>
RunAsync(input, channel).Result;
/// <summary>
/// Simulates a function/operation using the ToffoliSimulator as target machine.
/// It expects a single input: the name of the function/operation to simulate.
/// </summary>
public async Task<ExecutionResult> RunAsync(string input, IChannel channel)
{
var (name, args) = ParseInput(input);
var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol;
if (symbol == null) throw new InvalidOperationException($"Invalid operation name: {name}");
var qsim = new ToffoliSimulator();
qsim.DisableLogToConsole();
qsim.OnLog += channel.Stdout;
var value = await symbol.Operation.RunAsync(qsim, args);
return value.ToExecutionResult();
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Jupyter;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public class WhoMagic : AbstractMagic
{
public WhoMagic(ISnippets snippets) : base(
"who",
new Documentation {
Summary = "Provides actions related to the current workspace."
})
{
this.Snippets = snippets;
}
public ISnippets Snippets { get; }
public override ExecutionResult Run(string input, IChannel channel) =>
Snippets.Operations
.Select(op => op.FullName)
.OrderBy(name => name)
.ToArray()
.ToExecutionResult();
}
}

Просмотреть файл

@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
public class WorkspaceMagic : AbstractMagic
{
public WorkspaceMagic(IWorkspace workspace) : base(
"workspace",
new Documentation {
Summary = "Returns a list of all operations and functions defined in the current session, either interactively or loaded from the current workspace."
})
{
this.Workspace = workspace;
}
public IWorkspace Workspace { get; }
/// <summary>
/// Performs checks to verify if the Workspace is avaialble and in a success (no errors) state.
/// The method throws Exceptions if it finds it is not ready to execute.
/// </summary>
public void CheckIfReady()
{
if (Workspace == null)
{
throw new InvalidWorkspaceException($"Workspace is not ready. Try again.");
}
else if (Workspace.HasErrors)
{
throw new InvalidWorkspaceException(Workspace.ErrorMessages.ToArray());
}
}
public override ExecutionResult Run(string input, IChannel channel)
{
var (command, _) = ParseInput(input);
if (string.IsNullOrWhiteSpace(command))
{
// if no command, just return the current state.
}
else if ("reload" == command)
{
Workspace.Reload();
}
else
{
channel.Stderr($"Invalid action: {command}");
return ExecuteStatus.Error.ToExecutionResult();
}
CheckIfReady();
var names = Workspace?.AssemblyInfo?.Operations?
.Select(c => c.FullName)
.OrderBy(name => name)
.ToArray();
return names.ToExecutionResult();
}
}
}

Просмотреть файл

@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Newtonsoft.Json;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// A specialized resolver for MagicSymbols.
/// It finds all types that inherit MagicSymbol on the current Assembly
/// and all the Assemblies in global references (including those
/// added via nuget Packages).
/// </summary>
public class MagicSymbolResolver : ISymbolResolver
{
private AssemblyInfo kernelAssembly;
private Dictionary<AssemblyInfo, MagicSymbol[]> cache;
private IServiceProvider services;
private IReferences references;
private ILogger logger;
public MagicSymbolResolver(IServiceProvider services, ILogger<IQSharpEngine> logger)
{
this.cache = new Dictionary<AssemblyInfo, MagicSymbol[]>();
this.logger = logger;
this.kernelAssembly = new AssemblyInfo(typeof(IQSharpEngine).Assembly);
this.services = services;
this.references = services.GetService<IReferences>();
}
/// <summary>
/// Enumerates over all assemblies that should be searched
/// when resolving symbols.
/// </summary>
private IEnumerable<AssemblyInfo> RelevantAssemblies()
{
yield return this.kernelAssembly;
foreach (var asm in references.Assemblies)
{
yield return asm;
}
}
/// <summary>
/// Resolves a given symbol name into a Q# symbol
/// by searching through all relevant assemblies.
/// </summary>
/// <returns>
/// The symbol instance if resolution is successful, otherwise <c>null</c>.
/// </returns>
/// <remarks>
/// If the symbol to be resolved contains a dot,
/// it is treated as a fully qualified name, and will
/// only be resolved to a symbol whose name matches exactly.
/// Symbol names without a dot are resolved to the first symbol
/// whose base name matches the given name.
/// </remarks>
public ISymbol Resolve(string symbolName)
{
if (symbolName == null || !symbolName.TrimStart().StartsWith("%")) return null;
this.logger.LogDebug($"Looking for magic {symbolName}");
foreach (var magic in RelevantAssemblies().SelectMany(FindMagic))
{
if (symbolName.StartsWith(magic.Name))
{
this.logger.LogDebug($"Using magic {magic.Name}");
return magic;
}
}
return null;
}
/// <summary>
/// Finds the MagicSymbols inside an assembly, and returns an instance of each.
/// </summary>
public IEnumerable<MagicSymbol> FindMagic(AssemblyInfo assm)
{
var result = new MagicSymbol[0];
if (cache.TryGetValue(assm, out result))
{
return result;
}
this.logger.LogInformation($"Looking for MagicSymbols in {assm.Assembly.FullName}");
var magicTypes = assm.Assembly
.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(MagicSymbol)));
var allMagic = new List<MagicSymbol>();
foreach(var t in magicTypes)
{
try
{
var m = ActivatorUtilities.CreateInstance(services, t) as MagicSymbol;
allMagic.Add(m);
this.logger.LogInformation($"Found MagicSymbols {m.Name} ({t.FullName})");
}
catch (Exception e)
{
this.logger.LogWarning($"Unable to create instance of MagicSymbol {t.FullName}. Magic will not be enabled.\nMessage:{e.Message}");
}
}
result = allMagic.ToArray();
cache[assm] = result;
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Tests.IQsharp" + SigningConstants.PUBLIC_KEY)]

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Immutable;
using System.Collections.Generic;
using Microsoft.Jupyter.Core;
using Markdig;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// Encodes Q# symbols into plain text, e.g. for printing to the console.
/// </summary>
public class IQSharpSymbolToTextResultEncoder : IResultEncoder
{
public string MimeType => MimeTypes.PlainText;
public EncodedData? Encode(object displayable)
{
if (displayable is IQSharpSymbol symbol)
{
// TODO: display documentation here.
// We will need to parse the documentation to get out the summary, though.
return $"{symbol.Name}".ToEncodedData();
}
else return null;
}
}
/// <summary>
/// Encodes Q# symbols into HTML for display in Jupyter Notebooks and
/// other similar interfaces.
/// </summary>
public class IQSharpSymbolToHtmlResultEncoder : IResultEncoder
{
public string MimeType => MimeTypes.Html;
public EncodedData? Encode(object displayable)
{
if (displayable is IQSharpSymbol symbol)
{
var codeLink =
$"<a href=\"{symbol.Source}\"><i class=\"fa fas fa-code\"></i></a>";
return (
$"<h4><i class=\"fa fas fa-terminal\"></i> {symbol.Name} {codeLink}</h4>" +
Markdown.ToHtml(symbol.Documentation)
).ToEncodedData();
}
else return null;
}
}
}

Просмотреть файл

@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Common;
using Newtonsoft.Json;
namespace Microsoft.Quantum.IQSharp.Jupyter
{
/// <summary>
/// Represents a Q# code symbol (e.g. a function or operation name)
/// that can be used for documentation requests (`?`) or as a completion
/// suggestion.
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class IQSharpSymbol : ISymbol
{
[JsonIgnore]
public OperationInfo Operation { get; }
[JsonProperty("name")]
public string Name =>
Operation.FullName;
// TODO: serialize as stringenum.
[JsonProperty("kind")]
public SymbolKind Kind { get; private set; }
[JsonProperty("source")]
public string Source => Operation.Header.SourceFile.Value;
[JsonProperty("documentation")]
public string Documentation => String.Join("\n", Operation.Header.Documentation);
// TODO: expose documentation here.
public IQSharpSymbol(OperationInfo op)
{
if (op == null) { throw new ArgumentNullException(nameof(op)); }
this.Operation = op;
this.Kind = SymbolKind.Other;
}
}
/// <summary>
/// Resolves Q# symbols into Jupyter Core symbols to be used for
/// documentation requests.
/// </summary>
public class SymbolResolver : ISymbolResolver
{
private readonly IOperationResolver opsResolver;
/// <summary>
/// Constructs a new resolver that looks for symbols in a given
/// collection of snippets.
/// </summary>
/// <param name="snippets">
/// The collection of snippets to be used when resolving symbols.
/// </param>
public SymbolResolver(IOperationResolver opsResolver)
{
this.opsResolver = opsResolver;
}
/// <summary>
/// Creates a SymbolResolver from a Snippets implementation. Only used for testing.
/// </summary>
internal SymbolResolver(Snippets snippets)
{
this.opsResolver = new OperationResolver(snippets);
}
/// <summary>
/// Resolves a given symbol name into a Q# symbol
/// by searching through all relevant assemblies.
/// </summary>
/// <returns>
/// The symbol instance if resolution is successful, otherwise <c>null</c>.
/// </returns>
/// <remarks>
/// If the symbol to be resolved contains a dot,
/// it is treated as a fully qualified name, and will
/// only be resolved to a symbol whose name matches exactly.
/// Symbol names without a dot are resolved to the first symbol
/// whose base name matches the given name.
/// </remarks>
public ISymbol Resolve(string symbolName)
{
var op = opsResolver.Resolve(symbolName);
return op == null ? null : new IQSharpSymbol(op);
}
}
}

66
src/Jupyter/res/kernel.js Normal file
Просмотреть файл

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
define(
[
'codemirror/lib/codemirror',
'codemirror/addon/mode/simple'
],
(CodeMirror, Simple, CLike) => {
"use strict";
console.log(CodeMirror);
return {
onload: () => {
console.log(CodeMirror.defineSimpleMode);
CodeMirror.defineSimpleMode('qsharp', {
start: [
{
token: "comment",
// include % to support kata special commands
regex: /(\/\/|%).*/
},
{
token: "string",
regex: /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/
},
{
// a group of keywords that can typically occur in the beginning of the line but not in the end of a phrase
token: "keyword",
regex: /(^|\W)(?:namespace|open|as|operation|function|body|adjoint|controlled)\b/
},
{
token: "keyword",
regex: /\W(?:if|elif|else|repeat|until|fixup|for|in|return|fail)\b/
},
{
token: "keyword",
regex: /\W(?:Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\b/
},
{
token: "keyword",
regex: /\W(?:let|set|w\/|new|not|and|or|using|borrowing|newtype|mutable)\b/
},
{
token: "meta",
regex: /\W(?:Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\b/
},
{
token: "atom",
regex: /\W(?:true|false|Pauli(I|X|Y|Z)|One|Zero)\b/
},
{
token: "builtin",
regex: /(\\n|\W)(?:X|Y|Z|H|HY|S|T|SWAP|CNOT|CCNOT|MultiX|R|RFrac|Rx|Ry|Rz|R1|R1Frac|Exp|ExpFrac|Measure|M|MultiM)\b/
},
{
token: "builtin",
regex: /(\\n|\W)(?:Message|Length|Assert|AssertProb|AssertEqual)\b/
}
]
});
CodeMirror.defineMIME("text/x-qsharp", "qsharp");
}
};
}
);

Двоичные данные
src/Jupyter/res/logo-64x64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

7
src/Python/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
# Ignore autogenerated Python modules.
qsharp/version.py
# Python packaging artifacts
*.egg-info/
build/
dist/

29
src/Python/README.md Normal file
Просмотреть файл

@ -0,0 +1,29 @@
# Python Interoperability for Q# #
The `qsharp` package for Python provides interoperability with the Quantum Development Kit and with the Q# language, making it easy to simulate Q# operations and functions from within Python.
For details on how to get started with Python and Q#, please see the [Getting Started with Python guide](https://docs.microsoft.com/quantum/install-guide/python).
## Installing from Source ##
If you'd like to contribute to or experiment with the Python interoperability feature, it may be useful to install from source rather than from the `qsharp` package on the Python Package Index (PyPI).
To do so, make sure that you are in the `src` directory, and run `setup.py` with the `install` argument:
```bash
cd iqsharp/src/Python/
python setup.py install
```
## Building the `qsharp` Package ##
The Python interoperability feature uses a standard `setuptools`-based packaging strategy.
To build a platform-independent wheel, run the setup script with `bdist_wheel` instead:
```bash
cd iqsharp/src/Python/
python setup.py bdist_wheel
```
By default, this will create a `qsharp` wheel in `dist/` with the version number set to 0.0.0.1.
To provide a more useful version number, set the `ASSEMBLY_VERSION` environment variable before running `setup.py`.

Просмотреть файл

@ -0,0 +1,124 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# __init__.py: Root module for the qsharp package.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
"""
"""
## IMPORTS ##
import sys
from typing import List, Dict, Union
from collections import defaultdict
from distutils.version import LooseVersion
from qsharp.clients import _start_client
from qsharp.clients.iqsharp import IQSharpError
from qsharp.loader import QSharpCallable, QSharpModuleFinder
from qsharp.packages import Packages
from qsharp.types import Result, Pauli
try:
from qsharp.version import __version__
except:
__version__ = "<unknown>"
## EXPORTS ##
__all__ = [
'compile', 'reload',
'get_available_operations', 'get_available_operations_by_namespace',
'get_workspace_operations',
'packages',
'IQSharpError',
'Result', 'Pauli'
]
## FUNCTIONS ##
def compile(code : str) -> Union[QSharpCallable, List[QSharpCallable]]:
"""
Given a string containing Q# source code, compiles it into the current
workspace and returns one or more Q# callable objects that can be used to
invoke the new code.
:param code: A string containing Q# source code to be compiled.
:returns: A list of callables compiled from `code`, or a callable if exactly
one callable is found.
"""
ops = [
QSharpCallable(op, "snippets")
for op in client.compile(code)
]
if len(ops) == 1:
return ops[0]
else:
return ops
def reload() -> None:
"""
Reloads the current IQ# workspace, recompiling source files in the
workspace.
If the workspace fails to compile (e.g., because of a missing package),
Q# compilation errors are raised as an exception.
"""
client.reload()
def get_available_operations() -> List[str]:
"""
Returns a list containing the names of all operations and functions defined
in the current workspace, and that have been compiled dynamically from
snippets.
"""
return client.get_available_operations()
def get_workspace_operations() -> List[str]:
"""
Returns a list containing the names of all operations and functions defined
in the current workspace, excluding dynamically compiled snippets.
"""
return client.get_workspace_operations()
def get_available_operations_by_namespace() -> Dict[str, List[str]]:
"""
Returns a dictionary from namespaces to lists of operations and functions
defined in the current workspace that are members of each namespace.
"""
ops = get_available_operations()
by_ns = defaultdict(list)
for qualified_name in ops:
idx_last_dot = qualified_name.rfind(".")
ns_name = qualified_name[:idx_last_dot]
op_name = qualified_name[idx_last_dot + 1:]
by_ns[ns_name].append(op_name)
return dict(by_ns.items())
def component_versions() -> Dict[str, LooseVersion]:
"""
Returns a dictionary from components of the IQ# kernel to their
versions.
"""
versions = client.component_versions()
# Add in the qsharp Python package itself.
versions["qsharp"] = LooseVersion(__version__)
return versions
## STARTUP ##
client = _start_client()
packages = Packages(client)
# Make sure that we're last on the meta_path so that actual modules are loaded
# first.
sys.meta_path.append(QSharpModuleFinder())

Просмотреть файл

@ -0,0 +1,210 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# chemistry.py: enables using Q# chemistry library from Python.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
## IMPORTS ##
import qsharp
import json
import typing
from qsharp.serialization import map_tuples
from typing import List, Tuple, Dict, Iterable
from enum import Enum
## LOGGING ##
import logging
logger = logging.getLogger(__name__)
## EXPORTS ##
__all__ = [
'encode',
'load_broombridge',
'load_input_state',
'load_fermion_hamiltonian',
'IndexConvention',
'Broombridge',
'ProblemDescription',
'InputState',
'FermionHamiltonian'
]
## Enable the magic:
qsharp.packages.add("microsoft.quantum.chemistry.jupyter")
## Enums ##
class IndexConvention(Enum):
UpDown = 1
HalfUp = 2
## CLASSES ##
class FermionHamiltonian(object):
"""
Represents a fermion Hamiltonian.
"""
def __init__(self, data):
self.__dict__ = data
def __eq__(self, other):
if not isinstance(other, FermionHamiltonian):
# don't attempt to compare against unrelated types
return NotImplemented
return self.__dict__ == other.__dict__
def add_terms(self, fermion_terms : Iterable[Tuple[List[int], float]]) -> None:
"""
Adds terms to the fermion Hamiltonian.
"""
logger.info(f"Adding {len(fermion_terms)} terms to fermion Hamiltonian.")
result = qsharp.client._execute_magic(
'chemistry.fh.add_terms',
raise_on_stderr=True,
hamiltonian=self.__dict__,
fermion_terms=fermion_terms
)
self.__dict__ = result
class InputState(object):
"""
Represents an input state.
"""
def __init__(self, data: Dict):
self.__dict__ = data
def __eq__(self, other):
if not isinstance(other, InputState):
# don't attempt to compare against unrelated types
return NotImplemented
return self.__dict__ == other.__dict__
class ProblemDescription(object):
"""
Represents an electronic structure problem.
"""
def __init__ (self, data : Dict):
self.__dict__ = data
def __eq__(self, other):
if not isinstance(other, ProblemDescription):
# don't attempt to compare against unrelated types
return NotImplemented
return self.__dict__ == other.__dict__
def load_fermion_hamiltonian(self, index_convention : IndexConvention = IndexConvention.UpDown) -> FermionHamiltonian:
"""
Loads the fermion Hamiltonian associated with this electronic structure problem.
`index_convention` can be 'UpDown' or 'HalfUp'
"""
logger.info(f"Loading fermion Hamiltonian from problem description using index_convention '{index_convention.name}'.")
data = qsharp.client._execute_magic(
'chemistry.fh.load',
raise_on_stderr=True,
problem_description=self.__dict__,
index_convention=index_convention.name
)
return FermionHamiltonian(data)
def load_input_state(self, wavefunction_label : str = '', index_convention : IndexConvention = IndexConvention.UpDown) -> FermionHamiltonian:
"""
Loads the input state associated from this electronic structure problem with the corresponding label.
If `wavefunction_label` is not specified, it loads the greedy (Hartree-Fock) state.
`index_convention` can be 'UpDown' or 'HalfUp'
"""
logger.info(f"Loading input state '{wavefunction_label}' from problem description using index_convention '{index_convention.name}'.")
data = qsharp.client._execute_magic(
'chemistry.inputstate.load',
raise_on_stderr=True,
problem_description=self.__dict__,
wavefunction_label=wavefunction_label,
index_convention=index_convention.name
)
return InputState(data)
class Broombridge(object):
"""
Represents an instance of a broombridge schema data
"""
def __init__(self, data: Dict):
self.__dict__ = data
# translate problem_descriptions into the actual datastructure:
self.problem_description = [ ProblemDescription(p) for p in data["problem_description"] ]
def __eq__(self, other):
if not isinstance(other, FermionHamiltonian):
# don't attempt to compare against unrelated types
return NotImplemented
return self.__dict__ == other.__dict__
def load_fermion_hamiltonian(file_name: str, index_convention : IndexConvention = IndexConvention.UpDown) -> FermionHamiltonian:
"""
Loads the fermion Hamiltonian from the given file that contains broombridge data.
`index_convention` can be 'UpDown' or 'HalfUp'
"""
logger.info(f"Loading fermion Hamiltonian from '{file_name}' using index_convention '{index_convention.name}'.")
data = qsharp.client._execute_magic(
'chemistry.fh.load',
raise_on_stderr=True,
file_name=file_name,
index_convention=index_convention.name
)
return FermionHamiltonian(data)
def load_input_state(file_name: str, wavefunction_label : str = None, index_convention : IndexConvention = IndexConvention.UpDown) -> FermionHamiltonian:
"""
Loads the input state associated with the given labe from the given file that contains broombridge data..
If `wavefunction_label` is not specified, it loads the greedy (HartreeFock) state.
`index_convention` can be 'UpDown' or 'HalfUp'
"""
logger.info(f"Loading input state '{wavefunction_label}' from '{file_name}' using index_convention '{index_convention.name}'.")
data = qsharp.client._execute_magic(
'chemistry.inputstate.load',
raise_on_stderr=True,
file_name=file_name,
wavefunction_label=wavefunction_label,
index_convention=index_convention.name
)
return InputState(data)
def load_broombridge(file_name: str) -> Broombridge:
"""
Loads a Broombridge data file.
"""
logger.info(f"Loading broombridge data from '{file_name}'.")
# NB: we don't use the execute_magic method here, since we don't need to
# JSON serialize any arguments in this case.
data = qsharp.client._execute(f'%chemistry.broombridge {file_name}', raise_on_stderr=True)
return Broombridge(data)
def encode(hamiltonian : FermionHamiltonian, input_state : InputState) -> Tuple:
"""
Encodes the given Hamiltonian and input state using the Jordan Wigner encoding
that can be used to run chemistry simulations using Q#'s chemistry library.
"""
logger.info(f"Doing jw encoding.")
data = qsharp.client._execute_magic(
'chemistry.encode',
raise_on_stderr=True,
hamiltonian=hamiltonian.__dict__,
input_state=input_state.__dict__
)
return data

Просмотреть файл

@ -0,0 +1,49 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# __init__.py: Logic for launching and configuring Q# clients.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
import os
import sys
import time
import logging
from distutils.util import strtobool
def _start_client():
logger = logging.getLogger(__name__)
client_name = os.getenv("QSHARP_PY_CLIENT", "iqsharp")
if client_name == "iqsharp":
import qsharp.clients.iqsharp
client = qsharp.clients.iqsharp.IQSharpClient()
elif client_name == "mock":
import qsharp.clients.mock
client = qsharp.clients.mock.MockClient()
client.start()
# Check if the server is up and running:
server_ready = False
for idx_attempt in range(20):
try:
server_ready = client.is_ready()
if server_ready:
break
if idx_attempt == 0:
print("Preparing Q# environment...")
else:
print(".", end='', flush=True)
time.sleep(1)
except Exception as ex:
logger.debug('Exception while checking Q# environment.', exc_info=ex)
print("!", end='', flush=True)
time.sleep(1)
if not server_ready:
raise Exception("Q# environment was not available in allocated time.")
return client

Просмотреть файл

@ -0,0 +1,206 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# iqsharp.py: Client for the IQ# Jupyter kernel.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
import subprocess
import time
import http.client
import atexit
import json
import sys
import urllib.parse
import os
import jupyter_client
from io import StringIO
from collections import defaultdict
from typing import List, Dict, Callable, Any
from pathlib import Path
from distutils.version import LooseVersion
from qsharp.serialization import map_tuples, unmap_tuples
## LOGGING ##
import logging
logger = logging.getLogger(__name__)
## CLASSES ##
class IQSharpError(RuntimeError):
"""
Represents a Q# error passed by the IQ# kernel to the Python host.
"""
def __init__(self, iqsharp_errors : List[str]):
self.iqsharp_errors = iqsharp_errors
error_msg = StringIO()
error_msg.write("The Q# kernel raised the following errors:\n")
error_msg.writelines([
" " + msg for msg in iqsharp_errors
])
super().__init__(error_msg.getvalue())
class AlreadyExecutingError(IOError):
"""
Raised when the IQ# client is already executing a command and cannot safely
process an additional command.
"""
pass
class IQSharpClient(object):
kernel_manager = None
kernel_client = None
_busy : bool = False
def __init__(self):
self.kernel_manager = jupyter_client.KernelManager(kernel_name='iqsharp')
## Server Lifecycle ##
def start(self):
logger.info("Starting IQ# kernel...")
self.kernel_manager.start_kernel(extra_arguments=["--user-agent", "qsharp.py"])
self.kernel_client = self.kernel_manager.client()
atexit.register(self.stop)
def stop(self):
logger.info("Stopping IQ# kernel...")
try:
self.kernel_manager.shutdown_kernel()
except:
pass
def is_ready(self):
try:
result = self.component_versions(timeout=6)
logger.info(f"Q# version\n{result}")
except Exception as ex:
logger.info('Exception while checking if IQ# is ready.', exc_info=ex)
return
return True
def check_status(self):
if not self.kernel_manager.is_alive():
logger.debug("IQ# kernel is not running. Restarting.")
self.start()
## Public Interface ##
@property
def busy(self) -> bool:
return self._busy
def compile(self, body):
return self._execute(body)
def get_available_operations(self) -> List[str]:
return self._execute('%who', raise_on_stderr=False)
def get_operation_metadata(self, name : str) -> Dict[str, Any]:
return self._execute(f"?{name}")
def get_workspace_operations(self) -> List[str]:
return self._execute("%workspace")
def reload(self) -> None:
return self._execute(f"%workspace reload", raise_on_stderr=True)
def add_package(self, name : str) -> None:
return self._execute(f"%package {name}", raise_on_stderr=True)
def get_packages(self) -> List[str]:
return self._execute("%package", raise_on_stderr=False)
def simulate(self, op, **params) -> Any:
return self._execute_callable_magic('simulate', op, **params)
def toffoli_simulate(self, op, **params) -> Any:
return self._execute_callable_magic('toffoli', op, **params)
def estimate(self, op, **params) -> Dict[str, int]:
raw_counts = self._execute_callable_magic('estimate', op, **params)
# Convert counts to ints, since they get turned to floats by JSON serialization.
return {
operation_name: int(count)
for operation_name, count in raw_counts.items()
}
def component_versions(self, **kwargs) -> Dict[str, LooseVersion]:
"""
Returns a dictionary from components of the IQ# kernel to their
versions.
"""
versions = {}
def capture(msg):
# We expect a display_data with the version table.
if msg["msg_type"] == "display_data":
data = unmap_tuples(json.loads(msg["content"]["data"]["application/json"]))
for component, version in data["rows"]:
versions[component] = LooseVersion(version)
self._execute("%version", output_hook=capture, **kwargs)
return versions
## Internal-Use Methods ##
def _execute_magic(self, magic : str, raise_on_stderr : bool = False, **params) -> Any:
return self._execute(f'%{magic} {json.dumps(map_tuples(params))}', raise_on_stderr=raise_on_stderr)
def _execute_callable_magic(self, magic : str, op, raise_on_stderr : bool = False, **params) -> Any:
return self._execute_magic(f"{magic} {op._name}", raise_on_stderr=raise_on_stderr, **params)
def _execute(self, input, return_full_result=False, raise_on_stderr : bool = False, output_hook=None, **kwargs):
logger.debug(f"sending:\n{input}")
# make sure the server is still running:
try:
self.check_status()
except:
raise IQSharpError(["IQ# is not running."])
results = []
errors = []
if output_hook is None:
output_hook = self.kernel_client._output_hook_default
def _output_hook(msg):
if msg['msg_type'] == 'execute_result':
results.append(msg)
else:
if raise_on_stderr and msg['msg_type'] == 'stream' and msg['content']['name'] == 'stderr':
errors.append(msg['content']['text'])
else:
output_hook(msg)
try:
if self._busy:
# Trying to execute while already executing can corrupt the
# ordering of messages internally to ZeroMQ
# (see https://github.com/Microsoft/QuantumLibraries/issues/69),
# so we need to throw early rather than letting the problem
# propagate to a Jupyter protocol error.
raise AlreadyExecutingError("Cannot execute through the IQ# client while another execution is completing.")
self._busy = True
reply = self.kernel_client.execute_interactive(input, output_hook=_output_hook, **kwargs)
finally:
self._busy = False
logger.debug(f"received:\n{reply}")
# There should be either zero or one execute_result messages.
if errors:
raise IQSharpError(errors)
if results:
assert len(results) == 1
content = results[0]['content']
if 'application/json' in content['data']:
obj = unmap_tuples(json.loads(content['data']['application/json']))
else:
obj = None
return (obj, content) if return_full_result else obj
else:
return None

Просмотреть файл

@ -0,0 +1,101 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# mock.py: Placeholder client useful in running unit tests and in hosted CI.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
import atexit
import json
from typing import List, Dict, Callable, Any
from distutils.version import LooseVersion
## LOGGING ##
import logging
logger = logging.getLogger(__name__)
## CLASSES ##
class MockClient(object):
packages: List[str]
def __init__(self):
self.packages = []
## Server Lifecycle ##
def start(self):
logger.debug("MockClient.start called.")
atexit.register(self.stop)
def stop(self):
logger.debug("MockClient.stop called.")
def is_ready(self):
logger.debug("MockClient.is_ready called.")
return True
def check_status(self):
logger.debug("MockClient.check_status called.")
## Public Interface ##
@property
def busy(self) -> bool:
logger.debug("MockClient.busy accessed.")
return False
def compile(self, body):
logger.debug(f"MockClient.compile called with body:\n{body}")
return ["Workspace.Snippet.Example"]
def get_available_operations(self) -> List[str]:
logger.debug("MockClient.get_available_operations called.")
return ["A.B.C", "A.B.D", "A.E.F"]
def get_operation_metadata(self, name : str) -> Dict[str, Any]:
logger.debug(f"MockClient.get_operation_metadata called with name {name}.")
return {}
def get_workspace_operations(self) -> List[str]:
logger.debug("MockClient.get_workspace_operations called.")
return []
def reload(self) -> None:
logger.debug("MockClient.reload called.")
return None
def add_package(self, name : str) -> None:
logger.debug(f"MockClient.add_package called with name {name}.")
return self.packages.append(name)
def get_packages(self) -> List[str]:
logger.debug("MockClient.get_packages called.")
return self.packages
def simulate(self, op, **params) -> Any:
logger.debug(f"MockClient.simulate called with operation {op} and params:\n{params}")
return ()
def toffoli_simulate(self, op, **params) -> Any:
logger.debug(f"MockClient.toffoli_simulate called with operation {op} and params:\n{params}")
return ()
def estimate(self, op, **params) -> Dict[str, int]:
logger.debug(f"MockClient.estimate called with operation {op} and params:\n{params}")
return {
"Depth": 13,
"Width": 15
}
def component_versions(self, **kwargs) -> Dict[str, LooseVersion]:
"""
Returns a dictionary from components of the IQ# kernel to their
versions.
"""
logger.debug(f"MockClient.component_versions called with keyword arguments:\n{kwargs}")
return {}

119
src/Python/qsharp/loader.py Normal file
Просмотреть файл

@ -0,0 +1,119 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# loader.py: Support for exposing Q# namespaces as Python modules.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
import sys
from types import ModuleType, new_class
import importlib
from importlib.abc import MetaPathFinder, Loader
import qsharp
from typing import Optional, Any, Dict
import logging
logger = logging.getLogger(__name__)
class QSharpModuleFinder(MetaPathFinder):
def find_module(self, full_name : str, path : Optional[str] = None) -> Loader:
# We expose Q# namespaces as their own root-level packages.
# E.g.:
# >>> import Microsoft.Quantum.Intrinsic as mqi
# Thus, we need to check if the full name is one that that we can
# sensibly load before we proceed.
# To check the full name, we ask the client rather than going through
# the public API for the qsharp package, so that we can check if the
# client is currently busy. This can happen if anything below us in
# meta_path needs to handle an import during an execute; this is the
# case when ZeroMQ needs to import additional functionality from a
# Cython module to handle a message.
# See https://github.com/Microsoft/QuantumLibraries/issues/69 for an
# example of this failure modality.
# If the client is busy, we'll want to forego this request to find a
# module and return None early.
if qsharp.client.busy:
return None
# At this point, we should be safe to rely on the public API again.
ops = qsharp.get_available_operations_by_namespace()
if full_name not in ops:
# We may have been given part of the qualified name of a namespace.
# E.g., if we try to import Microsoft.Quantum.Intrinsic, we'll
# see calls with "Microsoft" and "Microsoft.Quantum" first.
if not any(
ns_name.startswith(full_name + ".")
for ns_name in ops
):
return None
return QSharpModuleLoader()
class QSharpModuleLoader(Loader):
def load_module(self, full_name : str):
logger.debug(f"Trying to load {full_name} as a Q# namespace.")
if full_name in sys.modules:
return sys.modules[full_name]
module = QSharpModule(full_name, full_name, self)
# Register the new module.
sys.modules.setdefault(full_name, module)
return module
class QSharpCallable(object):
_name : str
def __init__(self, callable_name : str, source : str):
self._name = callable_name
self.source = source
def __repr__(self) -> str:
return f"<Q# callable {self._name}>"
def simulate(self, **kwargs) -> Any:
"""
Executes this function or operation on the QuantumSimulator target
machine, returning its output as a Python object.
"""
return qsharp.client.simulate(self, **kwargs)
def toffoli_simulate(self, **kwargs) -> Any:
"""
Executes this function or operation on the ToffoliSimulator target
machine, returning its output as a Python object.
"""
return qsharp.client.toffoli_simulate(self, **kwargs)
def estimate_resources(self, **kwargs) -> Dict[str, int]:
return qsharp.client.estimate(self, **kwargs)
class QSharpModule(ModuleType):
_qs_name : str
def __init__(self, full_name : str, qs_name : str, loader : QSharpModuleLoader):
super().__init__(full_name)
self._qs_name = qs_name
self.__file__ = f"qsharp:{qs_name}"
self.__path__ = []
self.__loader__ = loader
def __getattr__(self, name):
ops = qsharp.get_available_operations_by_namespace()
if name in ops[self._qs_name]:
op_cls = new_class(name, (QSharpCallable, ))
# Copy over metadata from the operation's header.
metadata = qsharp.client.get_operation_metadata(f"{self._qs_name}.{name}")
op_cls.__doc__ = metadata.get('documentation', '')
op_cls.__file__ = metadata.get('source', None)
return op_cls(f"{self._qs_name}.{name}", "workspace")
raise AttributeError(f"Q# namespace {self._qs_name} does not contain a callable {name}.")
def __repr__(self) -> str:
return f"<module '{self._qs_name}' (Q# namespace)>"

Просмотреть файл

@ -0,0 +1,48 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# packages.py: Abstraction to represent the list of packages.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
from distutils.version import LooseVersion
from typing import Iterable, Tuple
## LOGGING ##
import logging
logger = logging.getLogger(__name__)
## CLASSES ##
class Packages(object):
"""
Represents the list of packages loaded into the current Q# session, and
allows for adding new packages from NuGet.org or any other configured feeds.
"""
def __init__(self, client):
self._client = client
def __iter__(self) -> Iterable[Tuple[str, LooseVersion]]:
for pkg_spec in self._client.get_packages():
name, version = pkg_spec.split("::", 1)
yield name, LooseVersion(version)
def __repr__(self) -> str:
return repr(list(self))
def __str__(self) -> str:
return str(list(self))
def add(self, package_name : str) -> None:
"""
Adds a NuGet package with the given package name to the current Q#
session, downloading the package from NuGet.org or any other configured
feeds as necessary.
"""
logger.info("Loading package: " + package_name)
pkgs=self._client.add_package(package_name)
logger.info("Loading complete: " + ';'.join(str(e) for e in pkgs))

Просмотреть файл

@ -0,0 +1,67 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# serialization.py: Utilities for mapping C# values to and from JSON.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
# Tuples are json encoded differently in C#, this makes sure they are in the right format.
def map_tuples(obj):
"""
Given a Python object to be serialized, converts any tuples to dictionaries
of a form expected by the Q# backend.
"""
if isinstance(obj, tuple):
result = {
'@type': 'tuple'
}
for i in range(len(obj)):
result[f"Item{i+1}"] = map_tuples(obj[i])
return result
elif isinstance(obj, list):
result = []
for i in obj:
result.append(map_tuples(i))
return result
elif isinstance(obj, dict):
result = {}
for i in obj:
result[i] = map_tuples(obj[i])
return result
else:
return obj
def unmap_tuples(obj):
"""
Given a Python object deserialized from JSON, converts any dictionaries that
represent tuples back to Python tuples. Dictionaries are considered to be
tuples if they either contain a key `@type` with the value `tuple`, or if
they have a key `item1`.
"""
if isinstance(obj, dict):
# Does this dict represent a tuple?
if obj.get('@type', None) in ('tuple', '@tuple') or 'Item1' in obj:
values = []
while True:
item = f"Item{len(values) + 1}"
if item in obj:
values.append(unmap_tuples(obj[item]))
else:
break
return tuple(values)
# Since this is a plain dict, unmap its values and we're good.
return {
key: unmap_tuples(value)
for key, value in obj.items()
}
elif isinstance(obj, list):
return [unmap_tuples(value) for value in obj]
else:
return obj

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/// Q# code should be in one or more .qs files that live
/// in the same directory as the python classical driver.
///
namespace Microsoft.Quantum.SanityTests {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
/// # Summary
/// The simplest program. Just generate a debug Message on the console.
operation HelloQ() : Unit
{
Message($"Hello from quantum world!");
}
/// # Summary
/// A more sophisticated program that shows how to
/// specify parameters, instantiate qubits, and return values.
operation HelloAgain(count: Int, name: String) : Result[] {
Message($"Hello {name} again!");
mutable r = new Result[count];
using (q = Qubit()) {
for (i in 1..count) {
ApplyIf(X, i == 2, q);
set r w/= i-1 <- M(q);
Reset(q);
}
}
return r;
}
/// # Summary
/// Checks that built-in complex types can be used as arguments.
operation HelloTuple(count: Int, tuples: (Result, String)[]) : (Result, String) {
return tuples[count];
}
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,260 @@
# © Microsoft
# MIT license
# Generated by nwchem version v...
"$schema": https://github.com/Microsoft/Quantum/blob/master/Chemistry/Schema/broombridge-0.2.schema.json
format:
version: "0.2" # required. Must match exactly
generator: # optional
source: nwchem # required if generator present
version: 0.1.2.3 # optional, but RFC 2119 SHOULD be SemVer
bibliography: # optional
- arXiv: 0123.4567v0 # optional, but must be of one of these forms
- doi: 10/11/12.13 # if present
- url: nwchem.org
problem_description:
- metadata: # required, but may be empty
molecule_name: LiH
basis_set: # optional
type: gaussian # required if basis_set is present
name: cc-pvdz # required if basis_set is present
geometry: # optional
units: angstrom # required if geometry is present
coordinate_system: cartesian # required if geometry is present
symmetry: c1 # required if geometry is present, but may be "c1"
atoms: # required if geometry is present
- name: Li # required
coords: [0.000000000000000, 0.000000000000000, 0.000000000000000] # required
- name: H
coords: [0.000000000000000, 0.000000000000000, 0.800000000000000]
coulomb_repulsion: # required
value: 1.9844146837 # required, but may be set to 0.
units: hartree # required
scf_energy: # required
value: -7.615770099223 # required, but may be set to 0.
units: hartree # required
scf_energy_offset: # required
units: hartree # required
value: 0 # required, but may be set to 0.
fci_energy: # optional
value: -7.634167267774 # optional
upper: -7 # required if fci_energy present
lower: -6 # required if fci_energy present
units: hartree # required if fci_energy present
# Total number of orbitals
n_orbitals: 6 # required
# Occupied orbitals
n_electrons: 4 # required
energy_offset: # required
value: 0 # required, but may be set to 0
units: hartree # required
# 1.) I have printed non-zero elements of Fock matrix (in the case of HF orbitals)
# the only non-zero elements correspond to HF orbitals energies (as in this case).
# I don't know what representation of 1-body Hamiltonian you are using. In case you
# want to get the core 1-body hamiltonian matrix h(i,j) you can easily express then
# through fock matrix and two-electron integrals (listed below) using formula:
# h(i,j)=f(i,j)-\sum_{m=1}^{N/2} [2*(ij|mm)-(im|mj)]
# where N corresponds to the number of electrons and N/2 desigantes the total
# number of occupied molecular orbitals (for h2o N/2=5)
# 2.) Two electron integrals are stored using Mullikan convention (ij|kl)
# /
# (ij|kl) = | dr1 dr2 psi_i(r1) psi_j(r1) 1/r12 psi_k(r2) psi_l(r2)
# /
# Using symmetries of these integrals, I have printed only a minimum set of these integrals,
# which means that each printed element of (ij|kl) corresponds to:
# (ij|kl), (ij|lk), (ji|kl), (ji|lk)
# (kl|ij), (kl|ji), (lk|ij), (lk|ji)
# All one- and two- electron integrals are listed below.
hamiltonian:
particle_hole_representation: # optional
units: hartree # required
format: sparse # required
values: # required
- [1, 2, 3, 4, 0.1, "-+++"] # - for annihilation opertor, + for creation operator
one_electron_integrals: # required
units: hartree # required
format: sparse # required
values: # required
# i j f(i,j)
- [1, 1, -5.0478572499]
- [1, 2, 0.1704971263]
- [1, 3, 0.1602915494]
- [1, 6, 0.1380352565]
- [2, 1, 0.1704971263]
- [2, 2, -1.8038123206]
- [2, 3, 0.0569382719]
- [2, 6, -0.4573620939]
- [3, 1, 0.1602915494]
- [3, 2, 0.0569382719]
- [3, 3, -1.1971184625]
- [3, 6, 0.0315192194]
- [4, 4, -1.2204338559]
- [5, 5, -1.2204338559]
- [6, 1, 0.1380352565]
- [6, 2, -0.4573620939]
- [6, 3, 0.0315192194]
- [6, 6, -1.0642805152]
two_electron_integrals: # required
# 2-electron integrals in Mulliken convention (ij|kj)
index_convention: mulliken # required
units: hartree # required
format: sparse # required
values: # required
# i j k l (ij|kl)
- [1, 1, 1, 1, 1.6264810823]
- [2, 1, 1, 1, -0.1864319375]
- [2, 1, 2, 1, 0.0458175647]
- [3, 1, 1, 1, -0.1105286548]
- [3, 1, 2, 1, 0.0125096577]
- [3, 1, 3, 1, 0.0169234452]
- [3, 1, 2, 2, -0.0287233594]
- [4, 1, 4, 1, 0.0100018867]
- [5, 1, 5, 1, 0.0100018867]
- [6, 1, 1, 1, -0.1460652459]
- [6, 1, 2, 1, 0.0338634205]
- [6, 1, 3, 1, 0.0134437424]
- [6, 1, 6, 1, 0.0285548992]
- [6, 1, 2, 2, 0.0095663414]
- [6, 1, 3, 2, -0.0076755300]
- [6, 1, 3, 3, -0.0063857786]
- [6, 1, 4, 4, -0.0051034944]
- [6, 1, 5, 5, -0.0051034944]
- [2, 2, 1, 1, 0.5129326927]
- [2, 2, 2, 1, 0.0159348112]
- [2, 2, 2, 2, 0.5165776344]
- [3, 2, 1, 1, -0.0053119016]
- [3, 2, 2, 1, -0.0076838242]
- [3, 2, 3, 1, 0.0012030748]
- [3, 2, 2, 2, -0.0338048110]
- [3, 2, 3, 2, 0.0092569900]
- [4, 2, 4, 1, 0.0088419589]
- [4, 2, 4, 2, 0.0291200165]
- [5, 2, 5, 1, 0.0088419589]
- [5, 2, 5, 2, 0.0291200165]
- [6, 2, 1, 1, 0.1659774136]
- [6, 2, 2, 1, 0.0111026934]
- [6, 2, 3, 1, -0.0200871413]
- [6, 2, 6, 1, 0.0104336880]
- [6, 2, 2, 2, 0.1592706872]
- [6, 2, 3, 2, -0.0264429080]
- [6, 2, 6, 2, 0.1229683564]
- [6, 2, 3, 3, 0.0288358883]
- [6, 2, 4, 4, 0.0370551252]
- [6, 2, 5, 5, 0.0370551252]
- [3, 3, 1, 1, 0.3900781727]
- [3, 3, 2, 1, -0.0178088073]
- [3, 3, 3, 1, 0.0043944950]
- [3, 3, 2, 2, 0.2554439927]
- [3, 3, 3, 2, -0.0057697625]
- [3, 3, 3, 3, 0.3365908615]
- [4, 3, 4, 1, 0.0101638887]
- [4, 3, 4, 2, 0.0202540046]
- [4, 3, 4, 3, 0.0430842942]
- [5, 3, 5, 1, 0.0101638887]
- [5, 3, 5, 2, 0.0202540046]
- [5, 3, 5, 3, 0.0430842942]
- [6, 3, 1, 1, 0.0224844942]
- [6, 3, 2, 1, -0.0156777409]
- [6, 3, 3, 1, 0.0060629955]
- [6, 3, 6, 1, -0.0089019097]
- [6, 3, 2, 2, -0.0447436867]
- [6, 3, 3, 2, 0.0036425215]
- [6, 3, 6, 2, -0.0278252358]
- [6, 3, 3, 3, 0.0359324325]
- [6, 3, 6, 3, 0.0272332115]
- [6, 3, 4, 4, 0.0006982988]
- [6, 3, 5, 5, 0.0006982988]
- [4, 4, 1, 1, 0.3958622722]
- [4, 4, 2, 1, -0.0061713879]
- [4, 4, 3, 1, -0.0035238763]
- [4, 4, 2, 2, 0.3085094405]
- [4, 4, 3, 2, -0.0005060608]
- [4, 4, 3, 3, 0.2825467114]
- [4, 4, 4, 4, 0.3129455112]
- [5, 4, 5, 4, 0.0168691395]
- [6, 4, 4, 1, -0.0015295889]
- [6, 4, 4, 2, -0.0127763068]
- [6, 4, 4, 3, -0.0094197774]
- [6, 4, 6, 4, 0.0125412340]
- [5, 5, 1, 1, 0.3958622722]
- [5, 5, 2, 1, -0.0061713879]
- [5, 5, 3, 1, -0.0035238763]
- [5, 5, 2, 2, 0.3085094405]
- [5, 5, 3, 2, -0.0005060608]
- [5, 5, 3, 3, 0.2825467114]
- [5, 5, 4, 4, 0.2792072321]
- [5, 5, 5, 5, 0.3129455112]
- [6, 5, 5, 1, -0.0015295889]
- [6, 5, 5, 2, -0.0127763068]
- [6, 5, 5, 3, -0.0094197774]
- [6, 5, 6, 5, 0.0125412340]
- [6, 6, 1, 1, 0.4487708891]
- [6, 6, 2, 1, 0.0161234675]
- [6, 6, 3, 1, -0.0239271257]
- [6, 6, 6, 1, 0.0150975260]
- [6, 6, 2, 2, 0.4557647335]
- [6, 6, 3, 2, -0.0340670290]
- [6, 6, 6, 2, 0.1568834019]
- [6, 6, 3, 3, 0.2501824010]
- [6, 6, 6, 3, -0.0387663626]
- [6, 6, 4, 4, 0.2781783402]
- [6, 6, 5, 5, 0.2781783402]
- [6, 6, 6, 6, 0.4391089602]
initial_state_suggestions: # optional. If not provided, spin-orbitals will be filled to minimize one-body diagonal term energies.
- label: "|G>"
method: sparse_multi_configurational # required
superposition:
- [1.0, "(1a)+","(2a)+","(3a)+","(4a)+","(5a)+","(6a)+","(1b)+","(2b)+","(3b)+","(4b)+","(5b)+","(6b)+","|vacuum>"]
- label: "|E>"
method: sparse_multi_configurational
superposition: # Suggested excited state
# Singles contribution
- [0.307397837154855,"(7a)+","(1a)","|G>"]
- [0.307397837154855,"(7b)+","(1b)","|G>"]
- [0.132355737522629,"(7a)+","(5a)","|G>"]
- [0.132355737522629,"(7b)+","(5b)","|G>"]
- [-0.119146974545900,"(11a)+","(5a)","|G>"]
- [-0.119146974545900,"(11b)+","(5b)","|G>"]
# Doubles contributions
- [-0.176269178877496,"(7a)+","(7b)+","(6b)","(2a)","|G>"]
- [-0.511320420474016,"(7a)+","(7b)+","(5b)","(3a)","|G>"]
- [-0.285084428017465,"(7a)+","(7b)+","(6b)","(4a)","|G>"]
- [-0.511320420474016,"(7a)+","(7b)+","(3b)","(5a)","|G>"]
- [-0.176269178877495,"(7a)+","(7b)+","(2b)","(6a)","|G>"]
- [-0.285084428017466,"(7a)+","(7b)+","(4b)","(6a)","|G>"]
- label : "|F>"
method: sparse_multi_configurational # required
superposition:
- [1.0, "(6b)+","(2a)","|E>"]
- label: "UCCSD |G>"
method: unitary_coupled_cluster
cluster_operator: # Initial state that cluster operator is applied to.
reference_state: [1.0, "(1a)+","(2a)+","(3a)+","(4a)+","(5a)+","(6a)+","(1b)+","(2b)+","(3b)+","(4b)+","(5b)+","(6b)+","|vacuum>"] # A one-body cluster term is t^{q}_{p} a^\dag_q a_p # A one-body unitary cluster term is t^{q}_{p}(a^\dag_q a_p- a^\dag_p a_q)
one_body_amplitudes: # t^{q}_{p} p q
- [0.1, "(1a)+", "(2a)"]
- [-0.2, "(1b)+", "(2a)"]
two_body_amplitudes: # t^{pq}_{rs} p q r s # If this is a PQQR term, the middle two indices must coincide.
- [-0.5, "(1a)+", "(2a)+", "(2b)", "(4b)"]
- [0.5, "(1a)+", "(3a)+", "(2a)", "(4b)"]

Просмотреть файл

@ -0,0 +1,82 @@
import logging
logging.basicConfig(level=logging.INFO)
import qsharp.chemistry
from qsharp.chemistry import load_broombridge, load_fermion_hamiltonian, load_input_state, encode, IndexConvention
print ( qsharp.component_versions() )
def test_load_broombridge():
"""
Checks that we can load a broombridge schema file.
"""
broombridge = load_broombridge("broombridge.yaml")
assert(len(broombridge.problem_description) == 1)
assert(len(broombridge.bibliography) == 3)
def test_load_fermion_hamiltonian():
"""
Checks that loading a fermion hamiltonian from file or from broombridge gives the same result.
"""
broombridge = load_broombridge("broombridge.yaml")
fh1 = broombridge.problem_description[0].load_fermion_hamiltonian()
fh2 = load_fermion_hamiltonian("broombridge.yaml")
assert(len(fh1.terms) == 6)
assert(fh1 == fh2)
fh3 = broombridge.problem_description[0].load_fermion_hamiltonian(IndexConvention.HalfUp)
fh4 = load_fermion_hamiltonian("broombridge.yaml", IndexConvention.HalfUp)
assert(len(fh3.terms) == 6)
assert(fh3 == fh4)
# should this be true? assert(fh3 != fh1)
def test_load_input_state():
"""
Checks that loading an input state from file or from broombridge gives the same result.
"""
broombridge = qsharp.chemistry.load_broombridge("broombridge.yaml")
is1 = broombridge.problem_description[0].load_input_state("UCCSD |G>")
is2 = load_input_state("broombridge.yaml", "UCCSD |G>")
assert(is1.Method == "UnitaryCoupledCluster")
assert(is1 == is2)
is3 = broombridge.problem_description[0].load_input_state("UCCSD |G>", IndexConvention.HalfUp)
is4 = load_input_state("broombridge.yaml", "UCCSD |G>", IndexConvention.HalfUp)
assert(is3.Method == "UnitaryCoupledCluster")
assert(is3 == is4)
assert(is1 != is4)
def test_load_greedy_state():
"""
Checks that not passing a wavefunction label generates the greedy input state.
"""
broombridge = qsharp.chemistry.load_broombridge("broombridge.yaml")
is1 = broombridge.problem_description[0].load_input_state("", IndexConvention.HalfUp)
is2 = load_input_state("broombridge.yaml", "", IndexConvention.HalfUp)
assert(is1.Method == "SparseMultiConfigurational")
assert(is1 == is2)
def test_jw_encode():
"""
Checks that we can encode a hamiltonian + input state
"""
broombridge = qsharp.chemistry.load_broombridge("broombridge.yaml")
fh1 = broombridge.problem_description[0].load_fermion_hamiltonian()
is1 = broombridge.problem_description[0].load_input_state()
jw = encode(fh1, is1)
assert(len(jw) == 4)

Просмотреть файл

@ -0,0 +1,114 @@
import qsharp
print ( qsharp.component_versions() )
def test_simulate():
"""
Checks that a simple simulate works correctly
"""
from Microsoft.Quantum.SanityTests import HelloQ
r = HelloQ.simulate()
assert r == ()
def test_toffoli_simulate():
foo = qsharp.compile("""
open Microsoft.Quantum.Measurement;
operation Foo() : Result {
using (q = Qubit()) {
X(q);
return MResetZ(q);
}
}
""")
assert foo.toffoli_simulate() == 1
def test_tuples():
"""
Checks that tuples are correctly encoded both ways.
"""
from Microsoft.Quantum.SanityTests import HelloTuple
r = HelloTuple.simulate(count=2, tuples=[(0, "Zero"), (1, "One"), (0, "Two"), (0, "Three")])
assert r == (0, "Two")
def test_estimate():
"""
Verifies that resource estimation works.
"""
from Microsoft.Quantum.SanityTests import HelloAgain
r = HelloAgain.estimate_resources(count=4, name="estimate test")
assert r['Measure'] == 8
assert r['QubitClifford'] == 1
assert r['BorrowedWidth'] == 0
def test_simple_compile():
"""
Verifies that compile works
"""
op = qsharp.compile( """
operation HelloQ() : Result
{
Message($"Hello from quantum world!");
return Zero;
}
""")
r = op.simulate()
assert r == 0
def test_multi_compile():
"""
Verifies that compile works
"""
ops = qsharp.compile( """
operation HelloQ() : Result
{
Message($"Hello from quantum world!");
return One;
}
operation Hello2() : Result
{
Message($"Will call hello.");
return HelloQ();
}
""")
assert "Hello2" == ops[0]._name
assert "HelloQ" == ops[1]._name
r = ops[1].simulate()
assert r == qsharp.Result.One
def test_chemistry_compile():
"""
Verifies that that adding packages and compile works
"""
qsharp.packages.add("microsoft.quantum.chemistry")
op = qsharp.compile( """
open Microsoft.Quantum.Characterization;
open Microsoft.Quantum.Chemistry.JordanWigner;
open Microsoft.Quantum.Simulation;
/// # Summary
/// We can now use Canon's phase estimation algorithms to
/// learn the ground state energy using the above simulation.
operation TrotterEstimateEnergy (qSharpData: JordanWignerEncodingData, nBitsPrecision : Int, trotterStepSize : Double) : (Double, Double) {
let (nSpinOrbitals, data, statePrepData, energyShift) = qSharpData!;
// Order of integrator
let trotterOrder = 1;
let (nQubits, (rescaleFactor, oracle)) = TrotterStepOracle(qSharpData, trotterStepSize, trotterOrder);
// Prepare ProductState
let statePrep = PrepareTrialState(statePrepData, _);
let phaseEstAlgorithm = RobustPhaseEstimation(nBitsPrecision, _, _);
let estPhase = EstimateEnergyWithAdiabaticEvolution(nQubits, statePrep, NoOp<Qubit[]>, oracle, phaseEstAlgorithm);
let estEnergy = estPhase * rescaleFactor + energyShift;
return (estPhase, estEnergy);
}
""")
assert op._name == "TrotterEstimateEnergy"

Просмотреть файл

@ -0,0 +1,74 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# test_serialization.py: Checks correctness of JSON serialization.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
## IMPORTS ##
import unittest
import json
from qsharp.serialization import map_tuples, unmap_tuples
class TestSerialization(unittest.TestCase):
def test_map_shallow_tuple(self):
self.assertEqual(
map_tuples((42, 'foo')),
{'@type': 'tuple', 'Item1': 42, 'Item2': 'foo'}
)
def test_map_deep_tuple(self):
actual = {
'foo': [1, 3.14, (42, 'baz')],
'bar': {'a': ('a', 'a'), 'b': ()}
}
expected = {
'foo': [1, 3.14, {'@type': 'tuple', 'Item1': 42, 'Item2': 'baz'}],
'bar': {
'a': {'@type': 'tuple', 'Item1': 'a', 'Item2': 'a'},
'b': {'@type': 'tuple'}
}
}
self.assertEqual(
map_tuples(actual), expected
)
def test_roundtrip_shallow_tuple(self):
actual = ('a', 3.14, False)
self.assertEqual(
unmap_tuples(map_tuples(actual)), actual
)
def test_roundtrip_dict(self):
actual = {'a': 'b', 'c': ('d', 'e')}
self.assertEqual(
unmap_tuples(map_tuples(actual)), actual
)
def test_roundtrip_deep_tuple(self):
actual = ('a', ('b', 'c'))
self.assertEqual(
unmap_tuples(map_tuples(actual)), actual
)
def test_roundtrip_very_deep_tuple(self):
actual = {
'a': {
'b': (
{
'c': ('d', ['e', ('f', 'g', 12, False)])
},
['h', {'g': ('i', 'j')}]
)
}
}
self.assertEqual(
unmap_tuples(map_tuples(actual)), actual
)
if __name__ == "__main__":
unittest.main()

Просмотреть файл

@ -0,0 +1,79 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# tomography.py: Single qubit tomography of Q# operations.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
## IMPORTS ##
import qsharp
import numpy as np
try:
import qinfer as qi
except ImportError:
qi = None
try:
import qutip as qt
except ImportError:
qt = None
def projector(P):
if qt is None:
raise ImportError("This function requires QuTiP.")
return (qt.qeye(2) + P) / 2.0
def single_qubit_process_tomography(
operation,
n_measurements=2000,
n_particles=4000
):
"""
:param operation: A Q# operation of type ((Pauli, Pauli) => Result) whose
inputs are named `prep` and `meas` (respectively), representing
a state preparation, evolution, and measurement.
"""
if qt is None:
raise ImportError("This function requires QuTiP.")
if qi is None:
raise ImportError("This function requires QInfer.")
print("Preparing tomography model...")
state_basis = qi.tomography.pauli_basis(1)
prior = qi.tomography.BCSZChoiDistribution(state_basis)
model = qi.tomography.TomographyModel(prior.basis)
updater = qi.SMCUpdater(model, n_particles, prior)
print("Performing tomography...")
for idx_experiment in range(n_measurements):
prep = qsharp.Pauli.sample()
meas = qsharp.Pauli.sample()
# Convert into a QuTiP object by using the standard transformation
# between state and process tomography.
qobj = 2.0 * qt.tensor(
projector(prep.as_qobj()).trans(), projector(meas.as_qobj())
)
expparams = np.array(
[(model.basis.state_to_modelparams(qobj),)],
dtype=model.expparams_dtype
)
datum = 1 - operation.simulate(prep=prep, meas=meas)
updater.update(datum, expparams)
return {
# We multiply by 2 to turn into a Choi–Jamiłkowski operator instead
# of a Choi–Jamiłkowski state.
'est_channel': 2.0 * model.basis.modelparams_to_state(updater.est_mean()),
# Returning the updater allows for exploring properties not extracted
# elsewhere.
'posterior': updater
}

Просмотреть файл

@ -0,0 +1,49 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# types.py: Provides types for interoperability with Q#.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
from enum import IntEnum
import random
try:
import qutip as qt
except ImportError:
qt = None
## ENUMS ######################################################################
class Result(IntEnum):
Zero = 0
One = 1
@classmethod
def sample(cls):
return random.choice(list(cls))
class Pauli(IntEnum):
I = 0b00
X = 0b01
Y = 0b11
Z = 0b10
@classmethod
def sample(cls):
return random.choice(list(cls))
if qt is not None:
def as_qobj(self):
if self == Pauli.I:
return qt.qeye(2)
elif self == Pauli.X:
return qt.sigmax()
elif self == Pauli.Y:
return qt.sigmay()
elif self == Pauli.Z:
return qt.sigmaz()
else:
raise ValueError(f"Unrecognized Pauli value {self}.")

Просмотреть файл

@ -0,0 +1,19 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# utils.py: Utilities internal to the qsharp package.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
import logging
logger = logging.getLogger(__name__)
from typing import Callable
## INTERNAL FUNCTIONS ##
def log_messages(data, action : Callable[[str], None] = logger.error):
msgs = data['messages']
for msg in msgs:
action(msg)

63
src/Python/setup.py Normal file
Просмотреть файл

@ -0,0 +1,63 @@
#!/bin/env python
# -*- coding: utf-8 -*-
##
# setup.py: Installs Python host functionality for Q#.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
## IMPORTS ##
import setuptools
import os
## VERSION INFORMATION ##
# Our build process sets the PYTHON_VERSION environment variable to a version
# string that is compatible with PEP 440, and so we inherit that version number
# here and propagate that to qsharp/version.py.
#
# To make sure that local builds still work without the same environment
# variables, we'll default to 0.0.0.1 as a development version.
version = os.environ.get('PYTHON_VERSION', '0.0.0.1')
with open('./qsharp/version.py', 'w') as f:
f.write(f'''# Auto-generated file, do not edit.
##
# version.py: Specifies the version of the qsharp package.
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
##
__version__ = "{version}"
''')
## DESCRIPTION ##
# The long description metadata passed to setuptools is used to populate the
# PyPI page for this package. Thus, we'll generate the description by using the
# same README.md file that we use in the GitHub repo.
with open("./README.md", "r") as fh:
long_description = fh.read()
## SETUPTOOLS INVOCATION ##
setuptools.setup(
name="qsharp",
version=version,
author="Microsoft",
description="Python client for Q#, a domain-specific quantum programming language",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/Quantum/QuantumLibraries",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
install_requires=[
'jupyter_client'
]
)

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Not following this convention.")]

Просмотреть файл

@ -0,0 +1,448 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Jupyter;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
namespace Tests.IQSharp
{
[TestClass]
public class IQSharpEngineTests
{
public IQSharpEngine Init(string workspace = "Workspace")
{
return Startup.Create<IQSharpEngine>(workspace);
}
public static void PrintResult(ExecutionResult result, MockChannel channel)
{
Console.WriteLine("Result:");
Console.WriteLine(JsonConvert.SerializeObject(result));
Console.WriteLine("Errors:");
foreach (var m in channel.errors) Console.WriteLine($" {m}");
Console.WriteLine("Messages:");
foreach (var m in channel.msgs) Console.WriteLine($" {m}");
}
public static string AssertCompile(IQSharpEngine engine, string source, params string[] expectedOps)
{
var channel = new MockChannel();
var response = engine.ExecuteMundane(source, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
CollectionAssert.AreEquivalent(expectedOps, response.Output as string[]);
return response.Output?.ToString();
}
public static string AssertSimulate(IQSharpEngine engine, string snippetName, params string[] messages)
{
var simMagic = new SimulateMagic(engine.SymbolsResolver);
var channel = new MockChannel();
var response = simMagic.Execute(snippetName, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
CollectionAssert.AreEqual(messages.Select(ChannelWithNewLines.Format).ToArray(), channel.msgs.ToArray());
return response.Output?.ToString();
}
public static string AssertEstimate(IQSharpEngine engine, string snippetName, params string[] messages)
{
var channel = new MockChannel();
var estimateMagic = new EstimateMagic(engine.SymbolsResolver);
var response = estimateMagic.Execute(snippetName, channel);
var result = response.Output as Dictionary<string, double>;
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.IsNotNull(result);
Assert.AreEqual(8, result.Count);
CollectionAssert.Contains(result.Keys, "T");
CollectionAssert.Contains(result.Keys, "CNOT");
CollectionAssert.AreEqual(messages.Select(ChannelWithNewLines.Format).ToArray(), channel.msgs.ToArray());
return response.Output?.ToString();
}
[TestMethod]
public void CompileOne()
{
var engine = Init();
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
}
[TestMethod]
public void CompileAndSimulate()
{
var engine = Init();
var simMagic = new SimulateMagic(engine.SymbolsResolver);
var channel = new MockChannel();
// Try running without compiling it, fails:
var response = simMagic.Execute("_snippet_.HelloQ", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
Assert.AreEqual(1, channel.errors.Count);
Assert.AreEqual(ChannelWithNewLines.Format($"Invalid operation name: _snippet_.HelloQ"), channel.errors[0]);
// Compile it:
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
// Try running again:
AssertSimulate(engine, "HelloQ", "Hello from quantum world!");
}
[TestMethod]
public void SimulateWithArguments()
{
var engine = Init();
// Compile it:
AssertCompile(engine, SNIPPETS.Reverse, "Reverse");
// Try running again:
var results = AssertSimulate(engine, "Reverse { \"array\": [2, 3, 4], \"name\": \"foo\" }", "Hello foo");
Assert.AreEqual("[4,3,2]", results);
}
[TestMethod]
public void Estimate()
{
var engine = Init();
var channel = new MockChannel();
// Compile it:
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
// Try running again:
AssertEstimate(engine, "HelloQ");
}
[TestMethod]
public void Toffoli()
{
var engine = Init();
var channel = new MockChannel();
// Compile it:
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
// Run with toffoli simulator:
var toffoliMagic = new ToffoliMagic(engine.SymbolsResolver);
var response = toffoliMagic.Execute("HelloQ", channel);
var result = response.Output as Dictionary<string, double>;
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(1, channel.msgs.Count);
Assert.AreEqual(ChannelWithNewLines.Format("Hello from quantum world!"), channel.msgs[0]);
}
[TestMethod]
public void DependsOnWorkspace()
{
var engine = Init();
// Compile it:
AssertCompile(engine, SNIPPETS.DependsOnWorkspace, "DependsOnWorkspace");
// Run:
var results = AssertSimulate(engine, "DependsOnWorkspace", "Hello Foo again!");
Assert.AreEqual("[Zero,One,Zero,Zero,Zero]", results);
}
[TestMethod]
public void UpdateSnippet()
{
var engine = Init();
// Compile it:
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
// Run:
AssertSimulate(engine, "HelloQ", "Hello from quantum world!");
// Compile it with a new code
AssertCompile(engine, SNIPPETS.HelloQ_2, "HelloQ");
// Run again:
AssertSimulate(engine, "HelloQ", "msg0", "msg1");
}
[TestMethod]
public void UpdateDependency()
{
var engine = Init();
// Compile HelloQ
AssertCompile(engine, SNIPPETS.HelloQ, "HelloQ");
// Compile something that depends on it:
AssertCompile(engine, SNIPPETS.DependsOnHelloQ, "DependsOnHelloQ");
// Compile new version of HelloQ
AssertCompile(engine, SNIPPETS.HelloQ_2, "HelloQ");
// Run dependency, it should reflect changes on HelloQ:
AssertSimulate(engine, "DependsOnHelloQ", "msg0", "msg1");
}
[TestMethod]
public void ReportWarnings()
{
var engine = Init();
{
var channel = new MockChannel();
var response = engine.ExecuteMundane(SNIPPETS.ThreeWarnings, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(3, channel.msgs.Count);
Assert.AreEqual(0, channel.errors.Count);
Assert.AreEqual("ThreeWarnings", new ListToTextResultEncoder().Encode(response.Output).Value.Data);
}
{
var channel = new MockChannel();
var response = engine.ExecuteMundane(SNIPPETS.OneWarning, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(1, channel.msgs.Count);
Assert.AreEqual(0, channel.errors.Count);
Assert.AreEqual("OneWarning", new ListToTextResultEncoder().Encode(response.Output).Value.Data);
}
}
[TestMethod]
public void ReportErrors()
{
var engine = Init();
var channel = new MockChannel();
var response = engine.ExecuteMundane(SNIPPETS.TwoErrors, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
Assert.AreEqual(2, channel.errors.Count);
}
[TestMethod]
public void TestPackages()
{
var engine = Init();
var snippets = engine.Snippets as Snippets;
var pkgMagic = new PackageMagic(snippets.GlobalReferences);
var channel = new MockChannel();
var response = pkgMagic.Execute("", channel);
var result = response.Output as string[];
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
Assert.IsNotNull(result);
Assert.AreEqual(1, result.Length);
// Try compiling TrotterEstimateEnergy, it should fail due to the lack
// of chemistry package.
response = engine.ExecuteMundane(SNIPPETS.TrotterEstimateEnergy, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
response = pkgMagic.Execute("microsoft.quantum.chemistry", channel);
result = response.Output as string[];
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Length);
// Now it should compile:
AssertCompile(engine, SNIPPETS.TrotterEstimateEnergy, "TrotterEstimateEnergy");
}
[TestMethod]
public void TestInvalidPackages()
{
var engine = Init();
var snippets = engine.Snippets as Snippets;
var pkgMagic = new PackageMagic(snippets.GlobalReferences);
var channel = new MockChannel();
var response = pkgMagic.Execute("microsoft.quantum", channel);
var result = response.Output as string[];
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
Assert.AreEqual(1, channel.errors.Count);
Assert.IsTrue(channel.errors[0].StartsWith("Unable to find package 'microsoft.quantum'"));
Assert.IsNull(result);
}
[TestMethod]
public void TestWho()
{
var snippets = Startup.Create<Snippets>("Workspace");
snippets.Compile(SNIPPETS.HelloQ);
var whoMagic = new WhoMagic(snippets);
var channel = new MockChannel();
// Check the workspace, it should be in error state:
var response = whoMagic.Execute("", channel);
var result = response.Output as string[];
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(5, result.Length);
Assert.AreEqual("HelloQ", result[0]);
Assert.AreEqual("Tests.qss.NoOp", result[4]);
}
[TestMethod]
public void TestWorkspace()
{
var engine = Init("Workspace.Chemistry");
var snippets = engine.Snippets as Snippets;
var wsMagic = new WorkspaceMagic(snippets.Workspace);
var pkgMagic = new PackageMagic(snippets.GlobalReferences);
var channel = new MockChannel();
var result = new string[0];
// Check the workspace, it should be in error state:
var response = wsMagic.Execute("reload", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
response = wsMagic.Execute("", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
// Try compiling a snippet that depends on a workspace that depends on the chemistry package:
response = engine.ExecuteMundane(SNIPPETS.DependsOnChemistryWorkspace, channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
Assert.AreEqual(0, channel.msgs.Count);
// Add dependencies:
response = pkgMagic.Execute("microsoft.quantum.chemistry", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
response = pkgMagic.Execute("microsoft.quantum.research", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
// Reload workspace:
response = wsMagic.Execute("reload", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
response = wsMagic.Execute("", channel);
result = response.Output as string[];
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
Assert.AreEqual(3, result.Length);
// Now compilation must work:
AssertCompile(engine, SNIPPETS.DependsOnChemistryWorkspace, "DependsOnChemistryWorkspace");
// Check an invalid command
response = wsMagic.Execute("foo", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Error, response.Status);
// Check that everything still works:
response = wsMagic.Execute("", channel);
PrintResult(response, channel);
Assert.AreEqual(ExecuteStatus.Ok, response.Status);
}
[TestMethod]
public void TestResolver()
{
var snippets = Startup.Create<Snippets>("Workspace");
snippets.Compile(SNIPPETS.HelloQ);
var resolver = new SymbolResolver(snippets);
// Intrinsics:
var symbol = resolver.Resolve("X");
Assert.IsNotNull(symbol);
Assert.AreEqual("Microsoft.Quantum.Intrinsic.X", symbol.Name);
// FQN Intrinsics:
symbol = resolver.Resolve("Microsoft.Quantum.Intrinsic.X");
Assert.IsNotNull(symbol);
Assert.AreEqual("Microsoft.Quantum.Intrinsic.X", symbol.Name);
// From namespace:
symbol = resolver.Resolve("Tests.qss.CCNOTDriver");
Assert.IsNotNull(symbol);
Assert.AreEqual("Tests.qss.CCNOTDriver", symbol.Name);
symbol = resolver.Resolve("CCNOTDriver");
Assert.IsNotNull(symbol);
Assert.AreEqual("Tests.qss.CCNOTDriver", symbol.Name);
/// From Canon:
symbol = resolver.Resolve("ApplyToEach");
Assert.IsNotNull(symbol);
Assert.AreEqual("Microsoft.Quantum.Canon.ApplyToEach", symbol.Name);
// Snippets:
symbol = resolver.Resolve("HelloQ");
Assert.IsNotNull(symbol);
Assert.AreEqual("HelloQ", symbol.Name);
// resolver is case sensitive:
symbol = resolver.Resolve("helloq");
Assert.IsNull(symbol);
// Invalid name
symbol = resolver.Resolve("foo");
Assert.IsNull(symbol);
}
[TestMethod]
public void TestResolveMagic()
{
var resolver = Startup.Create<MagicSymbolResolver>("Workspace.Broken");
var symbol = resolver.Resolve("%workspace");
Assert.IsNotNull(symbol);
Assert.AreEqual("%workspace", symbol.Name);
symbol = resolver.Resolve("%package") as MagicSymbol;
Assert.IsNotNull(symbol);
Assert.AreEqual("%package", symbol.Name);
Assert.IsNotNull(resolver.Resolve("%who"));
Assert.IsNotNull(resolver.Resolve("%estimate"));
Assert.IsNotNull(resolver.Resolve("%simulate"));
symbol = resolver.Resolve("%foo");
Assert.IsNull(symbol);
}
}
}
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

130
src/Tests/Mocks.cs Normal file
Просмотреть файл

@ -0,0 +1,130 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Microsoft.Jupyter.Core;
using Microsoft.Jupyter.Core.Protocol;
using Microsoft.Quantum.IQSharp;
#if TELEMETRY
using Microsoft.Applications.Events;
#endif
namespace Tests.IQSharp
{
public class MockKernelOptions : IOptions<KernelContext>
{
public KernelContext Value => new KernelContext();
}
public class MockNugetOptions : IOptions<NugetPackages.Settings>
{
public MockNugetOptions(string[] versions)
{
this.Value = new NugetPackages.Settings()
{
DefaultPackageVersions = versions
};
}
public NugetPackages.Settings Value { get; }
}
public class MockShell : IShellServer
{
public event Action<Message> KernelInfoRequest;
public event Action<Message> ExecuteRequest;
public event Action<Message> ShutdownRequest;
public void SendIoPubMessage(Message message)
{
throw new NotImplementedException();
}
public void SendShellMessage(Message message)
{
throw new NotImplementedException();
}
public void Start()
{
throw new NotImplementedException();
}
}
public class MockChannel : IChannel
{
public List<string> errors = new List<string>();
public List<string> msgs = new List<string>();
public void Display(object displayable)
{
throw new NotImplementedException();
}
public void Stderr(string message) => errors.Add(message);
public void Stdout(string message) => msgs.Add(message);
}
#if TELEMETRY
public class MockTelemetryLogger : ILogger
{
public List<EventProperties> Events = new List<EventProperties>();
public EVTStatus LogEvent(EventProperties evt)
{
Events.Add(evt);
return EVTStatus.OK;
}
public Task<SendResult> LogEventAsync(EventProperties evt)
{
Events.Add(evt);
return Task.FromResult(new SendResult(ResultStatus.Send));
}
public EVTStatus SetContext(string name, string value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, double value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, long value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, sbyte value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, short value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, int value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, byte value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, ushort value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, uint value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, bool value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, DateTime value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
public EVTStatus SetContext(string name, Guid value, PiiKind piiKind = PiiKind.None) =>
throw new NotImplementedException();
}
#endif
}

Просмотреть файл

@ -0,0 +1,207 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Microsoft.Quantum.IQSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NuGet.Configuration;
using NuGet.Packaging.Core;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
namespace Tests.IQSharp
{
[TestClass]
public class NugetPackagesTests
{
public NugetPackages Init()
{
var service = Startup.Create<References>("Workspace");
return service.Nugets;
}
[TestMethod]
public async Task GetLatestVersion()
{
var mgr = Init();
async Task TestOne(string pkg, string version)
{
var actual = await mgr.GetLatestVersion(pkg);
if (version == null)
{
Assert.IsNull(actual);
}
else
{
var expected = NuGetVersion.Parse(version);
Assert.IsNotNull(actual);
Assert.IsTrue(actual >= expected);
}
}
await TestOne("Microsoft.Quantum", null);
await TestOne("Newtonsoft.Json", "12.0.1");
}
[TestMethod]
public async Task GetDefaultVersion()
{
var version = "0.0.1101.3104-alpha";
var nuVersion = NuGetVersion.Parse(version);
var versions = new string[]
{
$"Microsoft.Quantum.Standard::{version}",
$"Microsoft.Quantum.Quantum.Development.Kit::{version}",
$"Microsoft.Quantum.Chemistry::{version}"
};
var mgr = new NugetPackages(new MockNugetOptions(versions), null);
Assert.AreEqual(nuVersion, await mgr.GetLatestVersion("Microsoft.Quantum.Standard"));
Assert.AreEqual(nuVersion, await mgr.GetLatestVersion("Microsoft.Quantum.Chemistry"));
Assert.AreEqual(nuVersion, await mgr.GetLatestVersion("microsoft.quantum.chemistry"));
Assert.AreEqual(nuVersion, await mgr.GetLatestVersion(" microsoft.quantum.chemistry "));
Assert.AreNotEqual(nuVersion, await mgr.GetLatestVersion("Microsoft.Quantum.Research"));
}
[TestMethod]
public async Task FindDependencies()
{
var mgr = Init();
var pkgId = new PackageIdentity("Microsoft.Quantum.Chemistry", NuGetVersion.Parse("0.4.1901.3104"));
using (var context = new SourceCacheContext())
{
var dependencies = new HashSet<SourcePackageDependencyInfo>(PackageIdentityComparer.Default);
await mgr.FindDependencies(pkgId, context, dependencies);
Assert.AreEqual(198, dependencies.Count());
}
}
[TestMethod]
public async Task ResolveDependencyGraph()
{
var mgr = Init();
var pkgId = new PackageIdentity("Microsoft.Quantum.Chemistry", NuGetVersion.Parse("0.4.1901.3104"));
using (var context = new SourceCacheContext())
{
var dependencies = new HashSet<SourcePackageDependencyInfo>(PackageIdentityComparer.Default);
await mgr.FindDependencies(pkgId, context, dependencies);
var list = mgr.ResolveDependencyGraph(pkgId, dependencies).ToArray();
Assert.AreEqual(198, dependencies.Count());
Assert.AreEqual(131, list.Length);
}
}
[TestMethod]
public async Task GetPackageDependencies()
{
var mgr = Init();
var pkgId = new PackageIdentity("Microsoft.Quantum.Chemistry", NuGetVersion.Parse("0.4.1901.3104"));
using (var context = new SourceCacheContext())
{
var dependencies = await mgr.GetPackageDependencies(pkgId, context);
Assert.AreEqual(131, dependencies.Count());
}
}
[TestMethod]
public async Task DownloadPackages()
{
var mgr = Init();
void ClearCache(string pkgName, NuGetVersion pkgVersion)
{
var pkg = new PackageIdentity(pkgName, pkgVersion);
var localPkg = LocalFolderUtility.GetPackageV3(SettingsUtility.GetGlobalPackagesFolder(mgr.NugetSettings), pkg, mgr.Logger);
if (localPkg != null)
{
Directory.Delete(Path.GetDirectoryName(localPkg.Path), true);
}
}
// Remove "Microsoft.Quantum.Chemistry" and "Microsoft.Quantum.Research" from local cache,
// Do this on an old version, to make sure we don't try to delete a loaded assembly:
var version = NuGetVersion.Parse("0.3.1811.2802-preview ");
ClearCache("Microsoft.Quantum.Chemistry", version);
ClearCache("Microsoft.Quantum.Research", version);
var researchPkg = new PackageIdentity("Microsoft.Quantum.Research", version);
var chemPkg = new PackageIdentity("Microsoft.Quantum.Chemistry", version);
using (var context = new SourceCacheContext())
{
var dependencies = await mgr.GetPackageDependencies(researchPkg, context);
Assert.IsFalse(mgr.IsInstalled(researchPkg));
Assert.IsFalse(mgr.IsInstalled(chemPkg));
await mgr.DownloadPackages(context, dependencies);
Assert.IsTrue(mgr.IsInstalled(researchPkg));
Assert.IsTrue(mgr.IsInstalled(chemPkg));
}
}
[TestMethod]
public async Task GetAssemblies()
{
var mgr = Init();
var pkgId = new PackageIdentity("Microsoft.Quantum.Chemistry", NuGetVersion.Parse("0.4.1901.3104"));
using (var context = new SourceCacheContext())
{
await mgr.Add(pkgId);
var libs = mgr.GetAssemblies(pkgId).Select(s => s.Assembly.GetName().Name).ToArray();
Assert.AreEqual(2, libs.Length);
CollectionAssert.Contains(libs, "Microsoft.Quantum.Chemistry.DataModel");
CollectionAssert.Contains(libs, "Microsoft.Quantum.Chemistry.Runtime");
}
}
[TestMethod]
public async Task AddPackage()
{
var mgr = Init();
using (var context = new SourceCacheContext())
{
var start = mgr.Items.Count();
await mgr.Add("Microsoft.Quantum.Research");
var libsResearch = mgr.Assemblies.Select(s => s.Assembly.GetName().Name).ToArray();
Assert.AreEqual(start + 1, mgr.Items.Count());
CollectionAssert.Contains(libsResearch, "Microsoft.Quantum.Research");
CollectionAssert.Contains(libsResearch, "Microsoft.Quantum.Chemistry.DataModel");
CollectionAssert.Contains(libsResearch, "Microsoft.Quantum.Chemistry.Runtime");
await mgr.Add("Microsoft.Quantum.Chemistry");
var libsChem = mgr.Assemblies.Select(s => s.Assembly.GetName().Name).ToArray();
Assert.AreEqual(start + 2, mgr.Items.Count());
// Chemistry assembly was already by research, no new Assemblies should be added:
Assert.AreEqual(libsResearch.Length, libsChem.Length);
// Make sure we're case insensitive.
await mgr.Add("microsoft.quantum.chemistry ");
Assert.AreEqual(start + 2, mgr.Items.Count());
}
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
namespace Tests.IQSharp
{
[TestClass]
public class PackagesControllerTest
{
public PackagesController Init(string root = @"Workspace")
{
return Startup.Create<PackagesController>(root);
}
[TestMethod]
public async Task ListPackages()
{
var controller = Init();
var response = await controller.List();
Assert.AreEqual(Status.success, response.status);
Assert.AreEqual(0, response.messages.Length);
Assert.IsTrue(response.result.Length == 1);
Assert.IsTrue(response.result[0].StartsWith("Microsoft.Quantum.Standard"));
}
[TestMethod]
public async Task AddPackage()
{
var controller = Init();
var response = await controller.List();
Assert.AreEqual(Status.success, response.status);
Assert.AreEqual(0, response.messages.Length);
Assert.IsTrue(response.result.Length == 1);
Assert.IsTrue(response.result[0].StartsWith("Microsoft.Quantum.Standard"));
response = await controller.Add("Microsoft.Quantum.Chemistry");
Assert.AreEqual(0, response.messages.Length);
Assert.IsTrue(response.result.Length == 2);
Assert.IsTrue(response.result[0].StartsWith("Microsoft.Quantum.Standard"));
Assert.IsTrue(response.result[1].StartsWith("Microsoft.Quantum.Chemistry"));
response = await controller.Add("Microsoft.Quantum.Research::0.4.1901.3104");
Assert.AreEqual(0, response.messages.Length);
Assert.IsTrue(response.result.Length == 3);
Assert.AreEqual("Microsoft.Quantum.Research::0.4.1901.3104", response.result[2]);
}
}
}
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

191
src/Tests/SNIPPETS.cs Normal file
Просмотреть файл

@ -0,0 +1,191 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
namespace Tests.IQSharp
{
public static class SNIPPETS
{
public static string HelloQ =
@"
/// # Summary
/// The simplest program. Just generate a debug Message on the console.
operation HelloQ() : Unit
{
Message($""Hello from quantum world!"");
}
";
public static string HelloQ_2 =
@"
/// # Summary
/// This to show that you can override the definition:
operation HelloQ() : Unit
{
Message($""msg0"");
Message($""msg1"");
}
";
public static string DependsOnHelloQ =
@"
/// # Summary
/// This to show that you can depend on other snippets:
operation DependsOnHelloQ() : Unit
{
HelloQ();
}
";
public static string Op1_Op2 =
@"
/// # Summary
/// This to show that you can define two operations in the same snippet:
operation Op1() : Unit
{
HelloQ();
}
operation Op2() : Unit
{
Op1();
}
";
public static string DependsOnWorkspace =
@"
/// # Summary
/// This to check that you can call operations from the workspace:
operation DependsOnWorkspace() : Result[]
{
return Tests.qss.HelloAgain(5, ""Foo"");
}
";
public static string OneWarning =
@"
/// # Summary
/// This script has one warning for using `()`
operation OneWarning() : ()
{
Message($""msg0"");
}
";
public static string ThreeWarnings =
@"
/// # Summary
/// This script has two warnings. One for using `()`, and two
/// for missing `(...)`
operation ThreeWarnings() : ()
{
body {
Message($""msg0"");
Message($""msg1"");
Message($""msg2"");
}
adjoint {}
}
";
public static string TwoErrors =
@"
/// # Summary
/// This script has errors:
/// * Unknown UDT (header)
/// * Missing semicolon
operation TwoErrors(foo: Bar) : ()
{
body {
Message($""msg0"");
Message(""msg1"") // Missing semicolon
Message($""msg2"");
}
}
";
public static string DependsOnChemistryWorkspace =
@"
/// # Summary
/// This scripts depend on the Chemistry.Workspace correctly loaded.
///
open Microsoft.Quantum.Chemistry.Samples;
open Microsoft.Quantum.Chemistry.JordanWigner;
operation DependsOnChemistryWorkspace() : ((JordanWignerEncodingData, Int, Double) => (Double, Double))
{
return TrotterEstimateEnergy;
}
";
public static string TrotterEstimateEnergy =
@"
/// # Summary
/// This script depends on the Chemistry package to compile.
open Microsoft.Quantum.Chemistry.JordanWigner;
open Microsoft.Quantum.Characterization;
open Microsoft.Quantum.Simulation;
operation TrotterEstimateEnergy (qSharpData: JordanWignerEncodingData, nBitsPrecision : Int, trotterStepSize : Double) : (Double, Double) {
let (nSpinOrbitals, data, statePrepData, energyShift) = qSharpData!;
// Order of integrator
let trotterOrder = 1;
let (nQubits, (rescaleFactor, oracle)) = TrotterStepOracle(qSharpData, trotterStepSize, trotterOrder);
// Prepare ProductState
let statePrep = PrepareTrialState(statePrepData, _);
let phaseEstAlgorithm = RobustPhaseEstimation(nBitsPrecision, _, _);
let estPhase = EstimateEnergy(nQubits, statePrep, oracle, phaseEstAlgorithm);
let estEnergy = estPhase * rescaleFactor + energyShift;
return (estPhase, estEnergy);
}
";
public static string InvalidFunctor =
@"
/// # Summary
/// This script has an operation can't have adjoint since it has a measurement inside.
operation InvalidFunctor(q: Qubit) : Unit {
body(...) {
let m = M(q);
if (m) { X(q); }
}
adjoint auto;
}
";
public static string Reverse =
@"
/// # Summary
/// This script returns the same array in reverse order.
/// Used to make sure we can pass arguments to snippets simulation.
operation Reverse(name : String, array: Int[]) : Int[] {
Message($""Hello {name}"");
let n = Length(array);
mutable m = new Int[n];
for(i in n-1..-1..0) {
set m w/= i <- array[n - 1 - i];
}
return m;
}
";
}
}

Просмотреть файл

@ -0,0 +1,105 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
namespace Tests.IQSharp
{
public class Complex : UDTBase<(double, double)>
{
public Complex((double, double) data) : base(data) {}
}
public class QubitState : UDTBase<(Complex, Complex)>
{
public QubitState((Complex, Complex) data) : base(data) {}
}
[TestClass]
public class SerializationTests
{
[TestMethod]
public async Task SerializeFlatUdtInstance()
{
var complex = new Complex((12.0, 1.4));
var token = JToken.Parse(JsonConvert.SerializeObject(complex, TupleConverters.Converters));
Assert.AreEqual(typeof(Complex).FullName, token["@type"].Value<string>());
Assert.AreEqual(12, token["Item1"].Value<double>());
Assert.AreEqual(1.4, token["Item2"].Value<double>());
}
[TestMethod]
public async Task DeserializeFlatUdtInstance()
{
var jsonData = @"
{
""@type"": ""COMPLEX"",
""Item1"": 12.0,
""Item2"": 1.4
}
".Replace("COMPLEX", typeof(Complex).FullName);
var complex = JsonConvert.DeserializeObject<Complex>(jsonData, TupleConverters.Converters);
Assert.AreEqual(new Complex((12.0, 1.4)), complex);
}
[TestMethod]
public async Task SerializeNestedUdtInstance()
{
var testValue = new QubitState((new Complex((0.1, 0.2)), new Complex((0.3, 0.4))));
var jsonData = JsonConvert.SerializeObject(testValue, TupleConverters.Converters);
System.Console.WriteLine(jsonData);
var token = JToken.Parse(jsonData);
Assert.AreEqual(typeof(QubitState).FullName, token["@type"].Value<string>());
Assert.AreEqual(typeof(Complex).FullName, token["Item1"]["@type"].Value<string>());
Assert.AreEqual(0.1, token["Item1"]["Item1"].Value<double>());
Assert.AreEqual(0.2, token["Item1"]["Item2"].Value<double>());
Assert.AreEqual(typeof(Complex).FullName, token["Item2"]["@type"].Value<string>());
Assert.AreEqual(0.3, token["Item2"]["Item1"].Value<double>());
Assert.AreEqual(0.4, token["Item2"]["Item2"].Value<double>());
}
[TestMethod]
public async Task DeserializeNestedUdtInstance()
{
var jsonData = @"
{
""@type"": ""STATE"",
""Item1"": {
""@type"": ""COMPLEX"",
""Item1"": 0.1,
""Item2"": 0.2
},
""Item2"": {
""@type"": ""COMPLEX"",
""Item1"": 0.3,
""Item2"": 0.4
}
}
"
.Replace("COMPLEX", typeof(Complex).FullName)
.Replace("STATE", typeof(QubitState).FullName);
var deserialized = JsonConvert.DeserializeObject<QubitState>(jsonData, TupleConverters.Converters);
Assert.AreEqual(
new QubitState((new Complex((0.1, 0.2)), new Complex((0.3, 0.4)))),
deserialized
);
}
}
}
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

Просмотреть файл

@ -0,0 +1,179 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Extensions = Microsoft.Quantum.IQSharp.Extensions;
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
namespace Tests.IQSharp
{
[TestClass]
public class SnippetsControllerTest
{
public SnippetsController Init(string workspace = "Workspace")
{
return Startup.Create<SnippetsController>(workspace);
}
public static async Task<string[]> AssertCompile(SnippetsController controller, string source, params string[] ops)
{
var response = await controller.Compile(source);
Console.WriteLine(JsonConvert.SerializeObject(response));
Assert.AreEqual(Status.success, response.status);
Assert.AreEqual(0, response.messages.Length);
foreach (var op in ops.OrderBy(o => o).Zip(response.result.OrderBy(o => o), (expected, actual) => new { expected, actual })) { Assert.AreEqual(op.expected, op.actual); }
return response.result;
}
public static async Task<object> AssertSimulate(SnippetsController controller, string snippetName, params string[] messages)
{
var response = await controller.Simulate(snippetName);
Console.WriteLine(JsonConvert.SerializeObject(response));
Assert.AreEqual(Status.success, response.status);
foreach (var m in messages.Zip(response.messages, (expected, actual) => new { expected, actual })) { Assert.AreEqual(m.expected, m.actual); }
return response.result;
}
[TestMethod]
public async Task CompileOne()
{
var controller = Init();
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
}
[TestMethod]
public async Task CompileAndSimulate()
{
var controller = Init();
// Try running without compiling it, fails:
var response = await controller.Simulate("_snippet_.HelloQ");
Assert.AreEqual(Status.error, response.status);
Assert.AreEqual(1, response.messages.Length);
Assert.AreEqual($"Invalid operation name: _snippet_.HelloQ", response.messages[0]);
// Compile it:
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
// Try running again:
await AssertSimulate(controller, "HelloQ", "Hello from quantum world!");
}
[TestMethod]
public async Task CompileInvalidFunctor()
{
var controller = Init();
var response = await controller.Compile(SNIPPETS.InvalidFunctor);
Console.WriteLine(JsonConvert.SerializeObject(response));
Assert.AreEqual(Status.error, response.status);
Assert.AreEqual(5, response.messages.Length);
}
[TestMethod]
public async Task CompileAndSimulateOnBrokenWorkspace()
{
var controller = Init("Workspace.Broken");
// Compile it:
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
// Try running:
await AssertSimulate(controller, "HelloQ", "Hello from quantum world!");
}
[TestMethod]
public async Task UpdateSnippet()
{
var controller = Init();
// Compile it:
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
// Run:
await AssertSimulate(controller, "HelloQ", "Hello from quantum world!");
// Compile it with a new code
await AssertCompile(controller, SNIPPETS.HelloQ_2, "HelloQ");
// Run again:
await AssertSimulate(controller, "HelloQ", "msg0", "msg1");
}
[TestMethod]
public async Task UpdateDependency()
{
var controller = Init();
// Compile HelloQ
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
// Compile something that depends on it:
await AssertCompile(controller, SNIPPETS.DependsOnHelloQ, "DependsOnHelloQ");
// Compile new version of HelloQ
await AssertCompile(controller, SNIPPETS.HelloQ_2, "HelloQ");
// Run dependency, it should reflect changes on HelloQ:
await AssertSimulate(controller, "DependsOnHelloQ", "msg0", "msg1");
}
[TestMethod]
public async Task MultipleSnippet()
{
var controller = Init();
// Compile it:
await AssertCompile(controller, SNIPPETS.HelloQ, "HelloQ");
// Compile snippet with dependencies and multiple operations:
await AssertCompile(controller, SNIPPETS.Op1_Op2, "Op1", "Op2");
// running Op2:
await AssertSimulate(controller, "Op2", "Hello from quantum world!");
}
[TestMethod]
public async Task DependsOnWorkspace()
{
var controller = Init();
// Compile it:
await AssertCompile(controller, SNIPPETS.DependsOnWorkspace, "DependsOnWorkspace");
// Run:
var results = await AssertSimulate(controller, "DependsOnWorkspace", "Hello Foo again!") as QArray<Result>;
Assert.IsNotNull(results);
Assert.AreEqual(5, results.Length);
}
[TestMethod]
public void IdentifyOperations()
{
var compiler = new CompilerService();
var elements = compiler.IdentifyElements(SNIPPETS.Op1_Op2).Select(Extensions.ToFullName).OrderBy(o => o).ToArray();
Assert.AreEqual(2, elements.Length);
Assert.AreEqual("SNIPPET.Op2", elements[1]);
}
}
}
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

49
src/Tests/Startup.cs Normal file
Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Jupyter;
namespace Tests.IQSharp
{
static class Startup
{
internal static ServiceProvider CreateServiceProvider(string workspaceFolder)
{
var dict = new Dictionary<string, string> { { "Workspace", Path.GetFullPath(workspaceFolder) } };
var config = new ConfigurationBuilder()
.AddInMemoryCollection(dict)
.AddJsonFile("appsettings.json")
.Build();
var services = new ServiceCollection();
services.Configure<Workspace.Settings>(config);
services.Configure<NugetPackages.Settings>(config);
services.AddLogging();
services.AddMocks();
services.AddIQSharp();
services.AddIQSharpKernel();
return services.BuildServiceProvider();
}
internal static T Create<T>(string workspaceFolder) =>
ActivatorUtilities.CreateInstance<T>(CreateServiceProvider(workspaceFolder));
public static void AddMocks(this IServiceCollection services)
{
services.AddSingleton<IShellServer>(new MockShell());
services.AddSingleton<IOptions<KernelContext>>(new MockKernelOptions());
}
}
}

178
src/Tests/TelemetryTests.cs Normal file
Просмотреть файл

@ -0,0 +1,178 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#if TELEMETRY
using System;
using Microsoft.Applications.Events;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.IQSharp.Jupyter;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tests.IQSharp
{
[TestClass]
public class TelemetryTests
{
public (Telemetry, IServiceProvider) StartTelemetry(string workspace = "Workspace")
{
var services = Startup.CreateServiceProvider(workspace);
var telemetry = new Telemetry(new MockTelemetryLogger());
telemetry.InitServices(services, null);
return (telemetry, services);
}
[TestMethod]
public void WorkspaceReload()
{
var (telemetry, services) = StartTelemetry();
var ws = services.GetService<IWorkspace>();
var logger = telemetry.Logger as MockTelemetryLogger;
Assert.AreEqual(0, logger.Events.Count);
ws.Reload();
Assert.AreEqual(1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.WorkspaceReload", logger.Events[0].Name);
Assert.AreEqual(PiiKind.GenericData, logger.Events[0].PiiProperties["Quantum.IQSharp.Workspace"]);
Assert.AreEqual("Workspace", logger.Events[0].Properties["Quantum.IQSharp.Workspace"]);
Assert.AreEqual("ok", logger.Events[0].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
}
[TestMethod]
public void InvalidWorkspaceReload()
{
var (telemetry, services) = StartTelemetry("Workspace.Broken");
var ws = services.GetService<IWorkspace>();
var logger = telemetry.Logger as MockTelemetryLogger;
Assert.AreEqual(0, logger.Events.Count);
ws.Reload();
Assert.AreEqual(1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.WorkspaceReload", logger.Events[0].Name);
Assert.AreEqual(PiiKind.GenericData, logger.Events[0].PiiProperties["Quantum.IQSharp.Workspace"]);
Assert.AreEqual("Workspace.Broken", logger.Events[0].Properties["Quantum.IQSharp.Workspace"]);
Assert.AreEqual("error", logger.Events[0].Properties["Quantum.IQSharp.Status"]);
Assert.IsTrue(logger.Events[0].Properties["Quantum.IQSharp.Errors"].ToString().StartsWith("QS"));
}
[TestMethod]
public void CompileCode()
{
var (telemetry, services) = StartTelemetry();
var snippets = services.GetService<ISnippets>();
var logger = telemetry.Logger as MockTelemetryLogger;
Assert.AreEqual(0, logger.Events.Count);
var count = 0;
snippets.Compile(SNIPPETS.HelloQ);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
count++;
snippets.Compile(SNIPPETS.HelloQ);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
count++;
snippets.Compile(SNIPPETS.DependsOnHelloQ);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
count++;
Assert.ThrowsException<CompilationErrorsException>(() => snippets.Compile(SNIPPETS.TwoErrors));
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("error", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
count++;
snippets.Compile(SNIPPETS.OneWarning);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
}
[TestMethod]
public void LoadPackage()
{
var (telemetry, services) = StartTelemetry();
var mgr = services.GetService<IReferences>();
var logger = telemetry.Logger as MockTelemetryLogger;
Assert.AreEqual(0, logger.Events.Count);
mgr.AddPackage("Microsoft.Quantum.Standard");
Assert.AreEqual(1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.PackageLoad", logger.Events[0].Name);
Assert.AreEqual("Microsoft.Quantum.Standard", logger.Events[0].Properties["Quantum.IQSharp.PackageId"]);
Assert.IsTrue(!string.IsNullOrWhiteSpace(logger.Events[0].Properties["Quantum.IQSharp.PackageVersion"]?.ToString()));
mgr.AddPackage("Microsoft.Quantum.Standard");
Assert.AreEqual(2, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.PackageLoad", logger.Events[0].Name);
Assert.AreEqual("Microsoft.Quantum.Standard", logger.Events[0].Properties["Quantum.IQSharp.PackageId"]);
Assert.IsTrue(!string.IsNullOrWhiteSpace(logger.Events[0].Properties["Quantum.IQSharp.PackageVersion"]?.ToString()));
}
[TestMethod]
public void JupyterActions()
{
var (telemetry, services) = StartTelemetry();
var engine = services.GetService<IExecutionEngine>() as IQSharpEngine;
var channel = new MockChannel();
var logger = telemetry.Logger as MockTelemetryLogger;
Assert.AreEqual(0, logger.Events.Count);
var count = 0;
engine.ExecuteMundane(SNIPPETS.HelloQ, channel);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Compile", logger.Events[count].Name);
Assert.AreEqual("ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
Assert.AreEqual("", logger.Events[0].Properties["Quantum.IQSharp.Errors"]);
count++;
engine.Execute("%simulate HelloQ", channel);
Assert.AreEqual(count + 1, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.Action", logger.Events[count].Name);
Assert.AreEqual("%simulate", logger.Events[count].Properties["Quantum.IQSharp.Command"]);
Assert.AreEqual("Ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
count++;
engine.Execute("%package Microsoft.Quantum.Standard", channel);
Assert.AreEqual(count + 2, logger.Events.Count);
Assert.AreEqual("Quantum.IQSharp.PackageLoad", logger.Events[count].Name);
Assert.AreEqual("Microsoft.Quantum.Standard", logger.Events[count].Properties["Quantum.IQSharp.PackageId"]);
Assert.IsTrue(!string.IsNullOrWhiteSpace(logger.Events[count].Properties["Quantum.IQSharp.PackageVersion"]?.ToString()));
count++;
Assert.AreEqual("Quantum.IQSharp.Action", logger.Events[count].Name);
Assert.AreEqual("%package", logger.Events[count].Properties["Quantum.IQSharp.Command"]);
Assert.AreEqual("Ok", logger.Events[count].Properties["Quantum.IQSharp.Status"]);
}
[TestMethod]
public void GetDeviceId()
{
var address = Telemetry.GetDeviceId();
Assert.IsTrue(!string.IsNullOrEmpty(address));
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<NoWarn>1701</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\build\DelaySign.cs" Link="Properties\DelaySign.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\Tool\appsettings.json" Link="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Jupyter\Jupyter.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
<ProjectReference Include="..\Tool\Tool.csproj" />
<ProjectReference Include="..\Web\Web.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Workspace.Broken\BasicOps.qs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Workspace.Broken\NoOp.qs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Workspace.Chemistry\Operation.qs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Workspace\BasicOps.qs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Workspace\NoOp.qs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Tests.qss {
open Microsoft.Quantum.Intrinsic;
//[ERROR]: MISSING Microsoft.Quantum.Standard;
/// # Summary
/// The simplest program. Just generate a debug Message on the console.
operation HelloQ() : Unit
{
Message($"Hello from quantum world!");
}
/// # Summary:
/// A more sophisticated program that shows how to
/// specify parameters, instantiate qubits, and return values.
operation HelloAgain(count: Int, name: String) : Result[]
{
Message($"Hello {name} again!");
mutable r = new Result[count];
using (q = Qubit()) {
for (i in 1..count) {
if (i == 2) { X(q); }
set r w/= i-1 <- M(q);
Reset(q);
}
}
return r;
}
operation CCNOTDriver(applyT : Bool) : Unit {
using(qubits = Qubit[3]) {
CCNOT(qubits[0], qubits[1], qubits[2]);
ApplyIf(T, applyT, qubits[0]);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Tests.qss {
open Microsoft.Quantum.Intrinsic;
operation NoOp () : Unit {
//[ERROR]: Can't return anything here:
return 5;
}
}

Просмотреть файл

@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// This file can only compile if both, the Chemistry and Research nuget packages
// are installed.
namespace Microsoft.Quantum.Chemistry.Samples {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Research.Chemistry;
open Microsoft.Quantum.Chemistry.JordanWigner;
open Microsoft.Quantum.Characterization;
open Microsoft.Quantum.Simulation;
//////////////////////////////////////////////////////////////////////////
// Using Trotterization //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// # Summary
/// We can now use Canon's phase estimation algorithms to
/// learn the ground state energy using the above simulation.
operation TrotterEstimateEnergy (qSharpData: JordanWignerEncodingData, nBitsPrecision : Int, trotterStepSize : Double) : (Double, Double) {
let (nSpinOrbitals, data, statePrepData, energyShift) = qSharpData!;
// Order of integrator
let trotterOrder = 1;
let (nQubits, (rescaleFactor, oracle)) = TrotterStepOracle(qSharpData, trotterStepSize, trotterOrder);
// Prepare ProductState
let statePrep = PrepareTrialState(statePrepData, _);
let phaseEstAlgorithm = RobustPhaseEstimation(nBitsPrecision, _, _);
let estPhase = EstimateEnergy(nQubits, statePrep, oracle, phaseEstAlgorithm);
let estEnergy = estPhase * rescaleFactor + energyShift;
return (estPhase, estEnergy);
}
//////////////////////////////////////////////////////////////////////////
// Using optimized Trotterization circuit ////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// # Summary
/// We can now use Canon's phase estimation algorithms to
/// learn the ground state energy using the above simulation.
operation OptimizedTrotterEstimateEnergy (qSharpData: JordanWignerEncodingData, nBitsPrecision : Int, trotterStepSize : Double) : (Double, Double) {
let (nSpinOrbitals, data, statePrepData, energyShift) = qSharpData!;
// Order of integrator
let trotterOrder = 1;
let (nQubits, (rescaleFactor, oracle)) = OptimizedTrotterStepOracle(qSharpData, trotterStepSize, trotterOrder);
// Prepare ProductState
let statePrep = PrepareTrialState(statePrepData, _);
let phaseEstAlgorithm = RobustPhaseEstimation(nBitsPrecision, _, _);
let estPhase = EstimateEnergy(nQubits, statePrep, oracle, phaseEstAlgorithm);
let estEnergy = estPhase * rescaleFactor + energyShift;
return (estPhase, estEnergy);
}
//////////////////////////////////////////////////////////////////////////
// Using Qubitization ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// # Summary
// Instead of implementing real-time evolution e^{iHt} with a Product formula,
// we may encode e^{isin^{-1}{H}} in a quantum walk created using
// the `Qubitization` procedure.
/// # Summary
/// We can now use Canon's phase estimation algorithms to
/// learn the ground state energy using the above simulation.
operation QubitizationEstimateEnergy (qSharpData: JordanWignerEncodingData, nBitsPrecision : Int) : (Double, Double) {
let (nSpinOrbitals, data, statePrepData, energyShift) = qSharpData!;
let (nQubits, (l1Norm, oracle)) = QubitizationOracle(qSharpData);
let statePrep = PrepareTrialState(statePrepData, _);
let phaseEstAlgorithm = RobustPhaseEstimation(nBitsPrecision, _, _);
let estPhase = EstimateEnergy(nQubits, statePrep, oracle, phaseEstAlgorithm);
// Note that the quantum walk applies e^{isin^{-1}{H/oneNorm}}, in contrast to
// real-time evolution e^{iHt} by a Product formula.
// Thus We obtain the energy estimate by applying Sin(.) to the phase estimate
// then rescaling by the coefficient one-norm of the Hamiltonian.
// We also add the constant energy offset to the estimated energy.
let estEnergy = Sin(estPhase) * l1Norm + energyShift;
// We return both the estimated phase, and the estimated energy.
return (estPhase, estEnergy);
}
}

Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Tests.qss {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
/// # Summary:
/// The simplest program. Just generate a debug Message on the console.
operation HelloQ() : Unit
{
Message($"Hello from quantum world!");
}
/// # Summary:
/// A more sophisticated program that shows how to
/// specify parameters, instantiate qubits, and return values.
operation HelloAgain(count: Int, name: String) : Result[]
{
Message($"Hello {name} again!");
mutable r = new Result[count];
using (q = Qubit()) {
for (i in 1..count) {
if (i == 2) { X(q); }
set r w/= i-1 <- M(q);
Reset(q);
}
}
return r;
}
operation CCNOTDriver(applyT : Bool) : Unit {
using(qubits = Qubit[3]) {
CCNOT(qubits[0], qubits[1], qubits[2]);
ApplyIf(T, applyT, qubits[0]);
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Tests.qss {
open Microsoft.Quantum.Intrinsic;
operation NoOp () : Unit {
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше