你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

如何使用 Q# 项目

使用 AzureQuantum Development Kit,可以定义Q#项目,这些项目是具有多个Q#文件的文件夹结构,这些文件可以访问彼此的操作和函数。 项目有助于在逻辑上组织源代码。 还可以将项目用作外部依赖项或可从外部源访问的自定义库。

项目 Q# 包含一个名为 Q# qsharp.json的清单文件,以及指定文件夹结构中的一个或多个 *.qs 文件。 当用户在 VS Code 中打开 *.qs 文件或设置 project_root Jupyter Notebook 或 Python 文件中时,编译器会在周围文件夹层次结构中搜索清单文件并确定项目的范围。 如果未找到清单文件,编译器将在单个文件模式下运行。 Q#可以在 VS Code 中手动或直接创建项目。

外部 Q# 项目是驻留在另一个目录或公共 GitHub 存储库中的标准 Q# 项目,并使用 export 语句定义外部程序可以访问哪些函数和操作。 程序将外部项目定义为其清单文件中的依赖项,并使用 import 语句访问外部项目中的项(操作、函数、结构和命名空间)。 有关详细信息,请参阅 将项目用作外部依赖项

先决条件

  • Azure 订阅中的 Azure Quantum 工作区。 若要创建工作区,请参阅创建 Azure Quantum 工作区
  • 安装了 Azure Quantum Development KitPython 扩展的 Visual Studio Code。
  • 如果计划将外部项目发布到公共 GitHub 存储库,则为 GitHub 帐户。

若要运行 Python 程序,还需要:

  • 安装了 Python 和 Pip 的 Python 环境。
  • Azure Quantum qsharpazure-quantum 包。

Q#定义项目

Q#项目由存在清单文件(名为qsharp.json)和 src 文件夹(其中包含Q#源文件)定义,这两个文件都必须位于项目的根文件夹中。 对于 Q# 程序和外部项目, Q# 编译器会自动检测项目文件夹。 对于 Python 程序和 Jupyter Notebook,必须使用调用指定 Q# 项目文件夹 qsharp.init 。 但是,对于所有类型的程序,项目的文件夹结构 Q# 保持不变。

显示项目的文件夹层次结构的 Q# 图片。

定义项目文件夹(Q# 程序)

在 VS Code 中打开 *.qs 文件时, Q# 编译器会在文件夹结构中向上搜索清单文件。 如果找到清单文件,编译器随后将包括 /src 目录或其任何子目录中的所有 Q# 文件。 每个文件的项都可用于项目中的所有其他文件。

例如,给定此文件夹结构:

  • Teleportation_project
    • qsharp.json
    • src
      • Main.qs
      • TeleportOperations
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

打开文件 /src/TeleportOperation/PrepareState/PrepareStateLib.qs 时, Q# 编译器:

  1. 检查 /src/TeleportOperation/PrepareState/ 是否为 qsharp.json。
  2. 检查 /src/TeleportOperation 是否有qsharp.json。
  3. 检查 /src 是否有qsharp.json。
  4. 检查 / qsharp.json。
  5. /根据清单文件的设置,建立为项目的根目录,并在项目根目录下包括所有 *.qs 文件。

创建清单文件

清单文件是一 个名为qsharp.json的简单.json 文件,可以选择包括 作者许可证lints 字段。 最小可行清单文件是字符串 {}。 在 VS Code 中创建 Q# 项目时,会为你创建一个最小的清单文件。

{}

清单文件示例

下面是清单文件如何定义项目范围的 Q# 一些示例。

  • 在此示例中, 作者 是唯一指定的字段,因此此目录中的所有 *.qs 文件及其所有子目录都包含在 Q# 项目中。

    {
        "author":"Microsoft",
        "license": "MIT"
    }
    
  • Q#在项目中,还可以使用清单文件微调 VS Code Q# Linter 设置。 默认情况下,三个 Linter 规则为:

    • needlessParens:default = allow
    • divisionByZero:default = warn
    • redundantSemicolons:default = warn

    使用清单文件,可以将每个规则设置为或allowwarnerror,例如

    {
        "author":"Microsoft",
        "lints": [
            {
              "lint": "needlessParens",
              "level": "allow"
            },
            {
              "lint": "redundantSemicolons",
              "level": "warn"
            },
            {
              "lint": "divisionByZero",
              "level": "error"
            }
          ]
    }
    
  • 还可以使用清单文件将外部 Q# 项目定义为依赖项,并远程访问该外部项目中的操作和函数。 有关详细信息,请参阅 将项目用作外部依赖项

Q# 项目要求和属性

以下要求和配置适用于所有 Q# 项目。

  • 要包含在项目中的所有 *.qs 文件都必须位于名为 src 的文件夹下,该文件夹必须位于项目的 Q#根文件夹下。 在 VS Code 中创建 Q# 项目时,会自动 /src 创建该文件夹。

  • 清单文件应与 src 文件夹位于同一级别。 在 VS Code 中创建 Q# 项目时,会自动创建最小文件。

  • 使用 import 语句引用项目中其他文件中的操作和函数。

    import MyMathLib.*;  //imports all the callables in the MyMathLib namespace
    ...
        Multiply(x,y);
    

    或者使用命名空间单独引用它们

    MyMathLib.Multiply(x,y);  
    

仅适用于 Q# 项目

  • 项目中只有一个 *.qs 文件 Q# 可以定义入口点,由单个 Main() 操作定义。
  • 具有入口点定义的 *.qs 文件可以位于清单文件下方的任何级别。
  • 从 *.qs 文件缓存的任何操作或函数在 Q# 项目中的任意位置都以 VS Code 中的预测文本形式显示。
  • 如果尚未导入所选操作或函数的命名空间,VS Code 会自动添加必要的 import 语句。

创建 Q# 项目的步骤

这些步骤适用于所有 Q# 项目。

  1. 在 VS Code 文件资源管理器中,右键单击要用于项目根文件夹的文件夹Q#,然后选择“创建Q#项目,或打开该文件夹,然后选择“查看>命令面板>Q#:创建Q#项目...”

  2. VS Code 在文件夹中创建最小清单文件,并添加包含/srcMain.qs模板文件的文件夹。

  3. 根据需要编辑清单文件。 请参阅 清单文件示例

  4. 在文件夹下/src添加和组织Q#源文件。

  5. 如果要从 Python 程序或 Jupyter Notebook 访问Q#项目,请使用 qsharp.init 设置根文件夹路径。 此示例假定程序位于项目的 /src 文件夹中 Q# :

    qsharp.init(project_root = '../Teleportation_project')
    
  6. 如果只 Q# 使用 VS Code 中的文件,则在打开 Q# 文件时,编译器将搜索清单文件,确定项目的根文件夹,然后扫描子文件夹以获取 *.qs 文件。

注意

还可以在步骤 2 中手动创建清单文件和 /src 文件夹。

示例项目

此量子传送程序是基于前面显示的单个文件夹结构的项目示例 Q# ,并在 VS Code 中的本地模拟器上运行。 若要在 Azure Quantum 硬件或第三方模拟器上运行程序,请参阅程序和 VSCode 入门Q#,了解编译程序并连接到 Azure 工作区的步骤。

此示例使用此目录结构:

  • Teleportation_project
    • qsharp.json
    • src
      • Main.qs
      • TeleportOperations
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

清单文件包含 作者许可证 字段:

{
    "author":"Microsoft",
    "license":"MIT"
}

Q# 源文件

Main.qs 主文件包含入口点,并引用 TeleportLib.qs 中的 TeleportOperations.TeleportLib 命名空间。


    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()操作,并从 PrepareStateLib.qs 调用PrepareBellPair()操作


    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 文件包含用于创建 Bell 对的标准可重用操作。

    
    operation PrepareBellPair(left : Qubit, right : Qubit) : Unit is Adj + Ctl {
        H(left);
        CNOT(left, right);
    }

运行程序

选择运行程序的环境的选项卡。

若要运行此程序,请在 VS Code 中打开 Main.qs 文件,然后选择“ 运行”。

将项目配置为 Q# 外部依赖项

Q#还可以将项目配置为其他项目的外部依赖项,其作用非常类似于库,其中外部Q#项目中的函数和操作可用于多个Q#项目。 外部依赖项可以驻留在驱动器共享上,也可以发布到公共 GitHub 存储库。

若要将 Q# 项目用作外部依赖项,需要:

  • 将外部项目添加为调用项目的清单文件中的依赖项。
  • 如果外部项目发布到 GitHub,请将“files”属性添加到外部项目的清单文件中。
  • 向外部项目添加 export 语句。
  • 向调用项目添加 import 语句。

配置清单文件

外部 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 的导入)导入的外部项目,“files”属性是可选的。 仅发布到 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 Microsoft.Quantum.Diagnostics; 替换 import Microsoft.Quantum.Diagnostics.*;。 另请注意,将 import 语句与标准 Q# 库一起使用时,可以将根命名空间缩短为 Std。 例如,import Microsoft.Quantum.Diagnostics.*; 可以写为 import Std.Diagnostics.*;

示例外部项目

对于此示例,你将使用与前面的示例相同的转接程序,但将呼叫程序和可调用者分开到不同的项目中。

  1. 在本地驱动器上创建两个文件夹,例如“Project_A”和“Project_B”。

  2. Q#按照步骤中的步骤创建项目,在每个文件夹中创建项目Q#

  3. Project_A 中,调用程序将以下代码复制到清单文件中,根据需要编辑Project_B的路径

    {
      "author": "Microsoft",
      "license": "MIT",
      "dependencies": {
        "MyTeleportLib": {
          "path": "/Project_B" 
          }
        }
      }    
    
  4. 在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);
        }
    }   
    
  5. 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中的程序调用。 由于它位于Project_B的本地范围内,因此该操作已可访问 Teleport

  6. 若要运行程序,请在 VS Code 中打开 /Project_A/Main.qs,然后选择“ 运行”。

项目和隐式命名空间

在 Q# 项目中,如果未在 *.qs 程序中指定命名空间,编译器将使用文件名作为命名空间。 引用可从外部依赖项调用的可调用项,然后使用语法 <dependencyName>。<命名空间>。<可>调用。 但是,如果文件名为“Main.qs”,则编译器假定命名空间,调用语法为 <dependencyName>。<可>调用,如上例 import MyTeleportLib.Teleport所示。

由于有多个项目文件并不常见,因此在引用可调用项时需要考虑正确的语法。 例如,在具有以下文件结构的项目中

  • src/
    • Main.qs
    • MathFunctions.qs

对外部依赖项的调用将是

import MyTeleportLib.MyFunction;        // "Main" namespace is implied

import MyTeleportLib.MathFunctions.MyFunction;   // "Math" namespace must be explicit 

有关命名空间行为的详细信息,请参阅 用户命名空间