你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
本文介绍如何创建、管理和共享 Q# 项目。 Q#项目是一个文件夹结构,其中包含多个Q#文件,可以访问彼此的作和函数。 项目有助于在逻辑上组织源代码。 还可以将项目用作可从外部源访问的自定义库。
先决条件
- Azure Quantum Azure 订阅中的工作区。 若要创建工作区,请参阅 “创建 Azure Quantum 工作区”。
- Visual Studio Code (VS Code) 安装了 Azure Quantum Development Kit 和 Python 扩展。
- 发布外部项目到公共 GitHub 存储库时,需拥有一个 GitHub 帐户。
若要运行 Python 程序,还需要:
安装了 Python 的 Python 环境。
具有可选扩展
azure的qdkPython 库。python -m pip install --upgrade qdk[azure]
项目工作原理Q#
Q#项目包含一个名为Q#的清单文件和一个或多个qsharp.json文件,这些文件位于指定的.qs文件夹结构中。 您可以手动创建Q#项目,也可以直接在VS Code中创建。
在 VS Code 中打开 .qs 文件时,编译器会在周围文件夹层级中搜索清单文件并确定项目的范围。 如果未找到清单文件,编译器将在单个文件模式下运行。
设置project_root一个或多个Jupyter NotebookPython文件时,编译器将在project_root文件夹中查找清单文件。
外部 Q# 项目是驻留在另一个目录或公共 GitHub 存储库中的标准 Q# 项目,充当自定义库。 外部项目使用 export 语句定义外部程序可访问的函数和作。 程序将外部项目定义为其清单文件中的依赖项,并使用 import 语句访问外部项目中的项,例如作、函数、结构和命名空间。 有关详细信息,请参阅 将项目用作外部依赖项。
定义Q#项目
Q#项目由存在清单文件(命名qsharp.json)和src文件夹定义,这两者都必须位于项目的根文件夹中。 该 src 文件夹包含 Q# 源文件。 对于 Q# 程序和外部项目, Q# 编译器会自动检测项目文件夹。 对于Python程序和Jupyter Notebook文件,您必须通过qsharp.init。 但是,项目的文件夹结构 Q# 对于所有类型的程序都是相同的。
定义项目文件夹(Q# 程序)
在 VS Code 中打开 .qs 文件时,Q# 编译器会在文件夹结构中向上遍历搜索清单文件。 如果编译器找到清单文件,编译器将包括目录中的所有 Q# 文件 /src 及其所有子目录。 每个文件中定义的项可供项目中的所有其他文件使用。
例如,请考虑以下文件夹结构:
-
Teleportation_project
- qsharp.json
-
src
- Main.qs
-
TeleportOperations
- TeleportLib.qs
-
PrepareState
- PrepareStateLib.qs
打开文件 /src/TeleportOperation/PrepareState/PrepareStateLib.qs 时,Q# 编译器执行以下操作:
- 检查
/src/TeleportOperation/PrepareState/的qsharp.json。 - 检查
/src/TeleportOperation的qsharp.json。 - 检查
/src的qsharp.json。 - 检查
/*的qsharp.json。 -
/根据清单文件的设置,建立为项目的根目录,并在项目根目录下包括所有.qs文件。
创建清单文件
清单文件是一个 JSON qsharp.json 文件,可选择性地包括 作者、 许可证和 lints 字段。 最小可行清单文件是字符串 {}。 在VS Code中创建Q#项目时,会为你创建一个最小化的清单文件。
{}
清单文件示例
以下示例显示如何通过清单文件来定义你的项目 Q# 的范围。
在此示例中, 作者 是唯一指定的字段,因此此目录中的所有
.qs文件及其子目录都包含在 Q# 项目中。{ "author":"Microsoft", "license": "MIT" }在Q#项目中,你还可以使用清单文件微调VS CodeQ# Linter 设置。 默认情况下,三个 Linter 规则为:
needlessParens:默认 =allowdivisionByZero:默认 =warnredundantSemicolons:默认 =warn可以将清单文件中的每个规则设置为
allow、warn或error。 例如:{ "author":"Microsoft", "lints": [ { "lint": "needlessParens", "level": "allow" }, { "lint": "redundantSemicolons", "level": "warn" }, { "lint": "divisionByZero", "level": "error" } ] }
还可以使用清单文件将外部 Q# 项目定义为依赖项,并远程访问该外部项目中的操作和函数。 有关详细信息,请参阅 将项目用作外部依赖项。
Q# 项目要求和属性
以下要求和配置适用于所有 Q# 项目。
要包含在项目中的所有
.qs文件都必须位于名为src的文件夹下,该文件夹必须位于项目的根文件夹 Q# 下。 在 Q# 中创建 VS Code项目时,/src将自动创建该文件夹。清单文件应与
src文件夹位于同一级别。 在创建Q#VS Code项目时,会自动创建最小文件。使用
import语句引用项目中其他文件中的操作和函数。import MyMathLib.*; //imports all the callables in the MyMathLib namespace ... Multiply(x,y);或者,使用命名空间单独引用它们。
MyMathLib.Multiply(x,y);
仅适用于 Q# 项目
- 您只能在项目中的一个
.qs文件中定义入口点操作,该操作是默认的Q#操作。 - 必须将具有入口点定义的文件放在
.qs清单文件下面的项目目录级别。 - 项目中所有Q#的操作和函数都缓存自
.qs,并在VS Code中的预测文本中显示。 - 如果所选作或函数的命名空间尚未导入,则 VS Code 会自动添加必要的
import语句。
如何创建 Q# 项目
若要创建 Q# 项目,请执行以下步骤:
在VS Code 文件资源管理器中,导航到您希望用作Q# 项目根文件夹的文件夹。
打开 “视图 ”菜单,然后选择 “命令面板”。
Enter QDK:创建 Q# 项目 ,然后按 Enter。 VS Code 在文件夹中创建最小清单文件,并添加
/src包含Main.qs模板文件的文件夹。编辑项目的Manifest文件。 请参阅清单文件示例。
将您的Q#源文件添加并组织在
/src文件夹下。如果从Python程序或Jupyter Notebook访问Q#项目,请使用
qsharp.init设置根文件夹路径。 假设此示例程序位于/src项目的 Q# 文件夹中:qsharp.init(project_root = '../Teleportation_project')如果您仅在 VS Code 中使用 Q# 文件,那么编译器在打开 Q# 文件时会搜索清单文件,以确定项目的根文件夹,然后扫描子文件夹以查找
.qs文件。
注意
还可以手动创建清单文件和 /src 文件夹。
示例项目
此量子传输程序是一个在本地模拟器Q#上运行的项目示例VS Code。 若要在
此示例具有以下目录结构:
-
Teleportation_project
- qsharp.json
-
src
- Main.qs
-
TeleportOperations
- TeleportLib.qs
-
PrepareState
- PrepareStateLib.qs
清单文件包含 作者 和 许可证 字段:
{
"author":"Microsoft",
"license":"MIT"
}
Q# 源文件
名为Main.qs的主文件包含入口点,并引用TeleportOperations.TeleportLib中的TeleportLib.qs命名空间。
import TeleportOperations.TeleportLib.Teleport; // references the Teleport operation from TeleportLib.qs
operation Main() : Unit {
use msg = Qubit();
use target = Qubit();
H(msg);
Teleport(msg, target); // calls the Teleport() operation from TeleportLib.qs
H(target);
if M(target) == Zero {
Message("Teleported successfully!");
Reset(msg);
Reset(target);
}
}
这个文件 TeleportLib.qs 定义操作 Teleport 并从 PrepareBellPair 文件调用 PrepareStateLib.qs 操作。
import TeleportOperations.PrepareState.PrepareStateLib.*; // references the namespace in PrepareStateLib.qs
operation Teleport(msg : Qubit, target : Qubit) : Unit {
use here = Qubit();
PrepareBellPair(here, target); // calls the PrepareBellPair() operation from PrepareStateLib.qs
Adjoint PrepareBellPair(msg, here);
if M(msg) == One { Z(target); }
if M(here) == One { X(target); }
Reset(here);
}
该 PrepareStateLib.qs 文件包含用于创建贝尔对的标准可重用操作。
operation PrepareBellPair(left : Qubit, right : Qubit) : Unit is Adj + Ctl {
H(left);
CNOT(left, right);
}
运行程序
选择用于运行程序的环境的选项卡。
若要运行此程序,请打开该文件Main.qsVS Code,然后选择“运行”。
将 Q# 项目配置为外部依赖项
可以将 Q# 配置为其他项目的外部依赖项,类似于一个库。 外部 Q# 项目中的函数和作可用于多个 Q# 项目。 外部依赖项可以驻留在驱动器共享上,也可以发布到公共 GitHub 存储库。
若要将 Q# 项目用作外部依赖项,必须:
- 将外部项目添加为调用项目的清单文件中的依赖项。
- 如果外部项目发布到 GitHub,则将 文件 属性添加到外部项目的清单文件中。
- 向外部项目添加
export语句。 - 向调用项目添加
import语句。
配置Manifest文件
外部 Q# 项目可以驻留在本地或网络驱动器共享上,也可以发布到公共 GitHub 存储库。
调用项目清单文件
若要将依赖项添加到驱动器共享上的外部项目,请在调用项目的清单文件中定义依赖项。
{
"author": "Microsoft",
"license": "MIT",
"dependencies": {
"MyDependency": {
"path": "/path/to/project/folder/on/disk"
}
}
}
在前面的清单文件中, MyDependency 是一个用户定义的字符串,用于在调用作时标识命名空间。 例如,如果创建名为 MyMathFunctions 的依赖项,则可以使用该依赖项 MyMathFunctions.MyFunction()调用函数。
若要将依赖项添加到发布到公共 GitHub 存储库的项目,请使用以下示例清单文件:
{
"author": "Microsoft",
"dependencies": {
"MyDependency": {
"github": {
"owner": "GitHubUser",
"repo": "GitHubRepoName",
"ref": "CommitHash",
"path": "/path/to/dependency"
}
}
}
}
注意
对于 GitHub 依赖项, ref 引用 GitHub refspec。 Microsoft 建议始终使用提交哈希,以便可以依赖特定版本的依赖项。
外部项目清单文件
如果外部 Q# 项目发布到公共 GitHub 存储库,则必须将 文件 属性添加到外部项目的清单文件中,包括项目中使用的所有文件。
{
"author": "Microsoft",
"license": "MIT",
"files": [ "src/MyMathFunctions.qs", "src/Strings/MyStringFunctions.qs" ]
}
文件属性对于通过"path"(即基于本地 filepath 的导入)导入的外部项目是可选的。
文件属性仅适用于发布到 GitHub 的项目。
使用 export 语句
若要使外部项目中的函数和操作可供调用的项目访问,请使用export语句。 可以导出文件中的任何或所有可调用对象。 不支持通配符语法,因此必须指定要导出的每个可调用项。
operation Operation_A() : Unit {
...
}
operation Operation_B() : Unit {
...
}
// makes just Operation_A available to calling programs
export Operation_A;
// makes Operation_A and Operation_B available to calling programs
export Operation_A, Operation_B, etc.;
// makes Operation_A available as 'OpA'
export Operation_A as OpA;
使用 import 语句
若要使外部依赖项中的项可用,请使用 import 调用程序中的语句。 该 import 语句使用为清单文件中的依赖项定义的命名空间。
例如,请考虑以下清单文件中的依赖项:
{
"author": "Microsoft",
"license": "MIT",
"dependencies": {
"MyMathFunctions": {
"path": "/path/to/project/folder/on/disk"
}
}
}
使用以下代码导入可调用项:
import MyMathFunctions.MyFunction; // imports "MyFunction()" from the namespace
...
该 import 语句还支持通配符语法和别名。
// imports all items from the "MyMathFunctions" namespace
import MyMathFunctions.*;
// imports the namespace as "Math", all items are accessible via "Math.<callable>"
import MyMathFunctions as Math;
// imports a single item, available in the local scope as "Add"
import MyMathFunctions.MyFunction as Add;
// imports can be combined on one line
import MyMathFunctions.MyFunction, MyMathFunctions.AnotherFunction as Multiply;
注意
当前使用的 open 语句 Q#(用于引用库和命名空间)仍受支持,但最终将弃用。 同时,可以选择更新当前文件以使用 import 语句。 例如,可以使用 open Std.Diagnostics; 替换 import Std.Diagnostics.*;。
示例外部项目
对于此示例,使用与前面的示例相同的远程传送程序,但将呼叫程序和可调用者分开到不同的项目中。
例如
Project_AProject_B,在本地驱动器上创建两个文件夹。在每个文件夹中创建一个项目 Q# 。 有关详细信息,请参阅 “如何创建 Q# 项目”中的步骤。
在调用程序
Project_A中,将以下代码复制到清单文件中,但根据需要编辑Project_B的路径:{ "author": "Microsoft", "license": "MIT", "dependencies": { "MyTeleportLib": { "path": "/Project_B" } } }在
Project_A中,将以下代码复制到Main.qs:import MyTeleportLib.Teleport; // imports the Teleport operation from the MyTeleportLib namespace defined in the manifest file operation Main() : Unit { use msg = Qubit(); use target = Qubit(); H(msg); Teleport(msg, target); // calls the Teleport() operation from the MyTeleportLib namespace H(target); if M(target) == Zero { Message("Teleported successfully!"); Reset(msg); Reset(target); } }在
Project_B中,复制以下代码到Main.qs:operation Teleport(msg : Qubit, target : Qubit) : Unit { use here = Qubit(); PrepareBellPair(here, target); Adjoint PrepareBellPair(msg, here); if M(msg) == One { Z(target); } if M(here) == One { X(target); } Reset(here); } operation PrepareBellPair(left : Qubit, right : Qubit) : Unit is Adj + Ctl { H(left); CNOT(left, right); } export Teleport; // makes the Teleport operation available to external programs注意
请注意,
PrepareBellPair不需要导出此操作,因为您的程序中并未直接调用Project_A中的此操作。 因为PrepareBellPair在Project_B的本地范围内,因此Teleport操作已可访问。若要运行程序,请打开
/Project_A/Main.qsVS Code并选择“运行”。
项目和隐式命名空间
在 Q# 项目中,如果未在 .qs 程序中指定命名空间,编译器将使用文件名作为命名空间。 然后,当您参考来自外部依赖项的可调用对象时,请使用语法 <dependencyName>.<namespace>.<callable>。 但是,如果文件已命名 Main.qs,则编译器假定命名空间和调用语法为 <dependencyName>.<callable>上例 import MyTeleportLib.Teleport所示。
由于可能有多个项目文件,因此在引用可调用项时需要考虑正确的语法。 例如,请考虑具有以下文件结构的项目:
-
/src
- Main.qs
- MathFunctions.qs
以下代码调用外部依赖项:
import MyTeleportLib.MyFunction; // "Main" namespace is implied
import MyTeleportLib.MathFunctions.MyFunction; // "Math" namespace must be explicit
有关命名空间行为的详细信息,请参阅 用户命名空间。