зеркало из https://github.com/microsoft/iqsharp.git
Initial commit.
This commit is contained in:
Родитель
3c3e4257b3
Коммит
cda82848d6
|
@ -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.
|
|
@ -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.
|
|
@ -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/
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"**/build/*.yml": "azure-pipelines"
|
||||
}
|
||||
}
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
||||
|
||||
|
||||
-------------------------------------------------------------------
|
|
@ -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.
|
|
@ -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/).
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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."
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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."
|
||||
}
|
|
@ -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) }
|
||||
|
|
@ -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
|
|
@ -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)"
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 2.3 KiB |
|
@ -0,0 +1,7 @@
|
|||
# Ignore autogenerated Python modules.
|
||||
qsharp/version.py
|
||||
|
||||
# Python packaging artifacts
|
||||
*.egg-info/
|
||||
build/
|
||||
dist/
|
|
@ -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 (Hartree–Fock) 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 {}
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче