Partilhar via


Como criar e gerenciar Q# projetos e bibliotecas personalizadas

Neste artigo, você aprenderá a criar, gerenciar e compartilhar Q# projetos. Q# Projetos são estruturas de pastas com vários Q# arquivos que podem acessar as operações e funções uns dos outros. Os projetos são úteis para organizar logicamente seu código-fonte. Você também pode usar projetos como bibliotecas personalizadas que podem ser acessadas de fontes externas.

Pré-requisitos

Para executar programas Python, você também precisa:

  • Um ambiente Python com Python e Pip instalados.
  • O Azure Quantum qsharp e azure-quantum pacotes.

Como Q# funcionam os projetos

Um Q# projeto contém um Q# arquivo de manifesto, chamado qsharp.json, e um ou mais arquivos *.qs em uma estrutura de pastas especificada. Quando um usuário abre um arquivo *.qs no VS Code, ou define o project_root em um arquivo Jupyter Notebook ou Python, o compilador procura o arquivo de manifesto na hierarquia de pastas ao redor e determina o escopo do projeto. Se nenhum arquivo de manifesto for encontrado, o compilador opera em um único modo de arquivo. Você pode criar um Q# projeto manualmente ou diretamente no VS Code.

Um projeto externo Q# é um projeto padrão Q# que reside em outro diretório ou em um repositório público do GitHub e atua como uma biblioteca personalizada. Um projeto externo usa export instruções para definir quais funções e operações podem ser acessadas por programas externos. Os programas definem o projeto externo como uma dependência em seu arquivo de manifesto e usam import instruções para acessar os itens (operações, funções, estruturas e namespaces) no projeto externo. Para obter mais informações, consulte Usando projetos como dependências externas.

Definir um Q# projeto

Um Q# projeto é definido pela presença de um arquivo de manifesto, chamado qsharp.json, e uma pasta src (que contém os Q# arquivos de origem), ambos os quais devem estar na pasta raiz do projeto. Para Q# programas e projetos externos, o Q# compilador deteta a pasta do projeto automaticamente. Para programas Python e Jupyter Notebooks, você deve Q# do projeto com uma qsharp.init chamada. A estrutura de pastas para um Q# projeto, no entanto, permanece a mesma para todos os tipos de programas.

A estrutura de pastas e a hierarquia de um Q# projeto.

Definição da pasta do projeto (Q# programas)

Quando um arquivo *.qs é aberto no VS Code, o compilador procura um arquivo de manifesto Q# na estrutura de pastas. Se encontrar um arquivo de manifesto, o compilador incluirá todos os Q# arquivos no diretório /src ou em qualquer um de seus subdiretórios. Os itens de cada arquivo são disponibilizados para todos os outros arquivos dentro do projeto.

Por exemplo, dada esta estrutura de pastas:

  • Teleportation_project
    • qsharp.json
    • SRC
      • Main.qs
      • Operações de Teletransporte
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

quando você abre o arquivo /src/TeleportOperation/PrepareState/PrepareStateLib.qs, o Q# compilador:

  1. Verifica /src/TeleportOperation/PrepareState/ para qsharp.json.
  2. Verifica /src/TeleportOperation para qsharp.json.
  3. Verifica /src para qsharp.json.
  4. Verifica / se há qsharp.json.
  5. Estabelece / como o diretório raiz do projeto e inclui todos os arquivos *.qs sob a raiz no projeto, de acordo com as configurações do arquivo de manifesto.

Criar um arquivo de manifesto

Um arquivo de manifesto é um arquivo de .json simples chamado qsharp.json que pode opcionalmente incluir campos autor, licença e fiapos . O arquivo de manifesto mínimo viável é a cadeia de caracteres {}. Quando você cria um Q# projeto no VS Code, um arquivo de manifesto mínimo é criado para você.

{}

Exemplos de arquivo de manifesto

A seguir estão alguns exemplos de como os arquivos de manifesto podem definir o escopo do seu Q# projeto.

  • Neste exemplo, autor é o único campo especificado e, portanto, todos os arquivos *.qs neste diretório e todos os seus subdiretórios são incluídos no Q# projeto.

    {
        "author":"Microsoft",
        "license": "MIT"
    }
    
  • Dentro de um Q# projeto, você também pode usar o arquivo de manifesto para ajustar as configurações do VS Code Q# Linter. Por padrão, as três regras do Linter são:

    • needlessParens: padrão = allow

    • divisionByZero: padrão = warn

    • redundantSemicolons: padrão = warn

      Usando o arquivo de manifesto, você pode definir cada regra como allow, warnou , por errorexemplo

      {
          "author":"Microsoft",
          "lints": [
              {
                "lint": "needlessParens",
                "level": "allow"
              },
              {
                "lint": "redundantSemicolons",
                "level": "warn"
              },
              {
                "lint": "divisionByZero",
                "level": "error"
              }
            ]
      }
      
  • Você também pode usar o arquivo de manifesto para definir um projeto externo Q# como uma dependência e acessar remotamente operações e funções nesse projeto externo. Para obter mais informações, consulte Usando projetos como dependências externas.

Q# Requisitos e propriedades do projeto

Os seguintes requisitos e configurações aplicam-se a todos os Q# projetos.

  • Todos os arquivos *.qs que você deseja incluir no projeto devem estar em uma pasta chamada src, que deve estar sob a pasta raiz do Q#. Quando você cria um Q# projeto no VS Code, a /src pasta é criada automaticamente.

  • O arquivo de manifesto deve estar no mesmo nível da pasta src . Quando você cria um Q# projeto no VS Code, um arquivo mínimo é criado automaticamente.

  • Use import instruções para fazer referência a operações e funções de outros arquivos no projeto.

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

    ou referenciando-os individualmente com o namespace

    MyMathLib.Multiply(x,y);  
    

Apenas para Q# projetos

  • Apenas um arquivo *.qs em um Q# projeto pode ter um ponto de entrada definido, definido por uma única Main() operação.
  • O arquivo *.qs com a definição do ponto de entrada pode ser localizado em qualquer nível abaixo do arquivo de manifesto.
  • Qualquer operação ou função armazenada em cache a partir de um arquivo *.qs em qualquer lugar do Q# projeto é exibida em texto preditivo no VS Code.
  • Se o namespace de uma operação ou função selecionada ainda não for importado, o VS Code adicionará automaticamente a instrução necessária import .

Etapas para criar um Q# projeto

Estas etapas aplicam-se a todos os Q# projetos.

  1. No explorador de ficheiros VS Code, clique com o botão direito do rato na pasta que pretende utilizar para a pasta raiz do projeto e selecione Criar projeto, ou abra a pasta e selecione Q#.Q#

  2. O VS Code cria um arquivo de manifesto mínimo na pasta e adiciona uma /src pasta com um arquivo de Main.qs modelo.

  3. Edite o arquivo de manifesto conforme necessário. Consulte Exemplos de arquivo de manifesto.

  4. Adicione e organize seus Q# arquivos de /src origem na pasta.

  5. Se você estiver acessando o Q# projeto a partir de um programa Python ou Jupyter Notebook, defina o caminho da pasta raiz usando qsharp.init. Este exemplo pressupõe que seu programa esteja na pasta /src do Q# projeto:

    qsharp.init(project_root = '../Teleportation_project')
    
  6. Se você estiver usando apenas Q# arquivos no VS Code, quando você abre um Q# arquivo, o compilador procura um arquivo de manifesto, determina a pasta raiz do projeto e, em seguida, verifica a subpasta em busca de arquivos *.qs.

Nota

Você também pode criar manualmente o arquivo de manifesto e a /src pasta na etapa 2.

Exemplo de projeto

Este programa de teletransporte quântico é um exemplo de um Q# projeto baseado na estrutura de pasta única mostrada anteriormente e é executado no simulador local no VS Code. Para executar o programa no hardware do Azure Quantum ou em simuladores de terceiros, consulte Introdução aos programas Q# e do VSCode para obter as etapas para compilar seu programa e conectar-se ao seu espaço de trabalho do Azure.

O exemplo usa esta estrutura de diretório:

  • Teleportation_project
    • qsharp.json
    • SRC
      • Main.qs
      • Operações de Teletransporte
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

O arquivo de manifesto contém os campos autor e licença :

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

Q# arquivos de origem

O arquivo principal, Main.qs, contém o ponto de entrada e faz referência ao TeleportOperations.TeleportLib namespace de 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 define a Teleport() operação e chama a PrepareBellPair() operação de 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);
    }

O arquivo PrepareStateLib.qs contém uma operação reutilizável padrão para criar um par Bell.

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

Executando os programas

Selecione a guia para o ambiente no qual você está executando o programa.

Para executar este programa, abra o arquivo Main.qs no VS Code e selecione Executar.

Configurando Q# projetos como dependências externas

Um Q# projeto também pode ser configurado como uma dependência externa para outros projetos, agindo como uma biblioteca, onde as funções e operações no projeto externo Q# são disponibilizadas para vários Q# projetos. Uma dependência externa pode residir em um compartilhamento de unidade ou publicada em um repositório público do GitHub.

Para usar um Q# projeto como uma dependência externa, você precisa:

  • Adicione o projeto externo como uma dependência no arquivo de manifesto do projeto chamador.
  • Se o projeto externo for publicado no GitHub, adicione a propriedade "files" ao arquivo de manifesto do projeto externo.
  • Adicione export instruções ao projeto externo.
  • Adicione import instruções ao projeto de chamada.

Configurando os arquivos de manifesto

Projetos externos Q# podem residir em um compartilhamento de unidade local ou de rede ou publicados em um repositório público do GitHub.

O arquivo de manifesto do projeto chamando

Para adicionar uma dependência a um projeto externo em um compartilhamento de unidade, defina a dependência no arquivo de manifesto do projeto chamador.

{
    "author": "Microsoft",
    "license": "MIT",
    "dependencies": {
        "MyDependency": {
            "path": "/path/to/project/folder/on/disk"
        }
    }
}

onde "MyDependency" é uma cadeia de caracteres definida pelo usuário que identifica o namespace ao chamar uma operação. Por exemplo, se você criar uma dependência chamada "MyMathFunctions", chamaria uma função dessa dependência com MyMathFunctions.MyFunction().

Para adicionar uma dependência a um projeto publicado em um repositório público do GitHub

{
    "author": "Microsoft",
    "dependencies": {
        "MyDependency": {
            "github": {
                "owner": "GitHubUser",
                "repo": "GitHubRepoName",
                "ref": "CommitHash",
                "path": "/path/to/dependency"
            }
        }
}

Nota

Para dependências do GitHub, "ref" refere-se a uma refspec do GitHub. A Microsoft recomenda sempre usar um hash de confirmação, para que você possa confiar em uma versão específica de sua dependência.

O arquivo de manifesto do projeto externo

Se seu projeto externo Q# for publicado em um repositório público do GitHub, você deverá adicionar a propriedade files ao arquivo de manifesto do projeto externo, incluindo todos os arquivos usados no projeto.

{
    "author": "Microsoft",
    "license": "MIT",
    "files": [ "src/MyMathFunctions.qs", "src/Strings/MyStringFunctions.qs" ]
}

A propriedade "files" é opcional para um projeto externo que está sendo importado via "path" (ou seja, uma importação local baseada em caminho de arquivo). Ele só é necessário para projetos publicados no GitHub.

Usando a instrução de exportação

Para tornar funções e operações em um projeto externo acessíveis para chamar projetos, use a export instrução. Você pode exportar qualquer um ou todos os chamáveis no arquivo. Não há suporte para sintaxe curinga, você deve especificar cada chamável para exportação.

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;             

Usando a instrução import

A partir do programa de chamada, você usa import instruções para disponibilizar itens de uma dependência externa. import As instruções usam o namespace definido para a dependência no arquivo de manifesto. Por exemplo, para esta dependência

{
    "author": "Microsoft",
    "license": "MIT",
    "dependencies": {
        "MyMathFunctions": {
            "path": "/path/to/project/folder/on/disk"
        }
    }
}

você importa callables como

import MyMathFunctions.MyFunction;  // imports "MyFunction()" from the namespace
...

A import instrução também suporta sintaxe curinga e aliases

// 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; 

Nota

A instrução usada open atualmente no Q#, que é usada para fazer referência a bibliotecas e namespaces, ainda é suportada, mas será preterida eventualmente. Enquanto isso, você pode, opcionalmente, atualizar seus arquivos atuais para usar a import instrução. Por exemplo, open Microsoft.Quantum.Diagnostics; pode ser substituído por import Microsoft.Quantum.Diagnostics.*;. Observe também que, ao usar a import instrução com as bibliotecas padrão Q# , você pode encurtar o namespace raiz para Std. Por exemplo, import Microsoft.Quantum.Diagnostics.*; pode ser escrito como import Std.Diagnostics.*;.

Exemplo de projeto externo

Neste exemplo, você usará o mesmo programa de teletransporte do exemplo anterior, mas separará o programa de chamada e os chamáveis em projetos diferentes.

  1. Crie duas pastas na sua unidade local, por exemplo "Project_A" e "Project_B".

  2. Crie um Q# projeto em cada pasta seguindo as etapas em Etapas para criar um Q# projeto.

  3. No Project_A, o programa de chamada, copie o código a seguir para o arquivo de manifesto, editando o caminho conforme necessário para Project_B

    {
      "author": "Microsoft",
      "license": "MIT",
      "dependencies": {
        "MyTeleportLib": {
          "path": "/Project_B" 
          }
        }
      }    
    
  4. No Project_A, copie o seguinte código para 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. No Project_B, copie o seguinte código para 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
    

    Nota

    Observe que a PrepareBellPair operação não precisa ser exportada porque não é chamada diretamente do seu programa no Project_A. Por estar no âmbito local do Project_B, já está acessível pela operação Teleport

  6. Para executar o programa, abra /Project_A/Main.qs no VS Code e selecione Executar.

Projetos e namespaces implícitos

Em Q# projetos, se um namespace não for especificado em um programa *.qs, o compilador usará o nome do arquivo como namespace. A referência a um chamável a partir de uma dependência externa usa a sintaxe <dependencyName>.<espaço para nomes>.<exigível>. No entanto, se o arquivo for chamado "Main.qs", o compilador assumirá o namespace e a sintaxe de chamada será <dependencyName>.<chamável>, como no exemplo anterior, import MyTeleportLib.Teleport.

Como não é incomum ter vários arquivos de projeto, você precisa levar em conta a sintaxe correta ao fazer referência a chamáveis. Por exemplo, em um projeto com a seguinte estrutura de arquivos

  • /src
    • Main.qs
    • MathFunctions.qs

os apelos à dependência externa seriam

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

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

Para obter mais informações sobre o comportamento do namespace, consulte Namespaces de usuário.