Compartilhar via


Como criar e gerenciar Q# projetos e bibliotecas personalizadas

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

Pré-requisitos

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

  • Um ambiente Python com Python e Pip instalado.

  • A biblioteca qdkPython com o opcional extra azure.

    python -m pip install --upgrade "qdk[azure]"
    

Como Q# funcionam os projetos

Um Q# projeto contém um Q# arquivo de manifesto, nomeado qsharp.jsone um ou mais .qs arquivos em uma estrutura de pasta especificada. Você pode criar um Q# projeto manualmente ou diretamente em VS Code.

Quando você abre um .qs arquivo em VS Code, o compilador pesquisa a hierarquia de pastas em busca do arquivo de manifesto e determina o escopo do projeto. Se nenhum arquivo de manifesto for encontrado, o compilador operará em um único modo de arquivo.

Quando você define o project_root em um arquivo Jupyter Notebook ou Python, o compilador procura o arquivo de manifesto na pasta project_root.

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 as funções e as operações acessíveis 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 no projeto externo, como operações, funções, structs e namespaces. 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, nomeado qsharp.jsone uma src pasta, que deve estar na pasta raiz do projeto. A src pasta contém os arquivos de origem Q# . Para Q# programas e projetos externos, o Q# compilador detecta a pasta do projeto automaticamente. Para Python programas e Jupyter Notebook arquivos, você deve especificar a pasta do Q# projeto com um qsharp.init comando. No entanto, a estrutura de pastas de um Q# projeto é a mesma para todos os tipos de programas.

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

Definir a pasta do projeto (Q# programas)

Quando você abre um arquivo .qs em VS Code, o compilador Q# pesquisa na estrutura de pastas, subindo, por um arquivo de manifesto. Se o compilador encontrar um arquivo de manifesto, o compilador incluirá todos os Q# arquivos no /src diretório e todos os subdiretórios dele. Os itens definidos em cada arquivo ficam disponíveis para todos os outros arquivos dentro do projeto.

Por exemplo, considere a seguinte estrutura de pastas:

  • Teleportation_project
    • qsharp.json
    • src
      • Main.qs
      • TeleportOperações
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

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

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

Criar um arquivo de manifesto

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

{}

Exemplos de arquivo de manifesto

Os exemplos a seguir mostram como os arquivos de manifesto podem definir o escopo do seu Q# projeto.

  • Neste exemplo, o autor é o único campo especificado, portanto, todos os .qs arquivos neste diretório e 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 manifesto para ajustar as configurações do VS CodeQ# Linter. Por padrão, as três regras do Linter são:

    • needlessParens: padrão = allow

    • divisionByZero: padrão = warn

    • redundantSemicolons: padrão = warn

      Você pode definir cada regra no arquivo de manifesto como allow, warnou error. Por exemplo:

      {
          "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 requisitos e configurações a seguir se aplicam a todos os Q# projetos.

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

  • O arquivo de manifesto deve estar no mesmo nível da src pasta. Quando você cria um projeto em Q#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 faça referência a eles individualmente usando o namespace.

    MyMathLib.Multiply(x,y); 
    

Somente para Q# projetos

  • Você pode definir uma operação de ponto de entrada em somente um arquivo .qs em um projeto Q#, que é a operação padrão Main().
  • Você deve colocar o arquivo .qs com a definição do ponto de entrada em uma camada abaixo do diretório do projeto onde está o arquivo de manifesto.
  • Todas as operações e funções no Q# projeto que são armazenadas em cache de uma .qs exibição no texto preditivo em VS Code.
  • Se o namespace de uma operação ou função selecionada ainda não foi importado, o VS Code adicionará automaticamente a instrução necessária import.

Como criar um Q# projeto

Para criar um Q# projeto, siga estas etapas:

  1. No explorador VS Code de arquivos, vá para a pasta que você deseja usar como a pasta raiz do Q# projeto.

  2. Abra o menu Exibir e escolha Paleta de Comandos.

  3. InsiraQDK: crie Q# o projeto e pressione Enter. VS Code cria um arquivo de manifesto mínimo na pasta e adiciona uma /src pasta com um Main.qs arquivo de modelo.

  4. Edite o arquivo de manifesto do seu projeto. Consulte Exemplos de arquivo de manifesto.

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

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

    qsharp.init(project_root = '../Teleportation_project')
    
  7. Se você estiver usando apenas arquivos Q# em VS Code, o compilador procurará um arquivo de manifesto ao abrir um arquivo Q#, determinará a pasta raiz do projeto e, em seguida, examinará a subpasta em busca de arquivos .qs.

Observação

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

Projeto de exemplo

Este programa de teletransporte quântico é um exemplo de um Q# projeto executado no simulador local em VS Code. Para executar o programa em hardware Azure Quantum ou simuladores de terceiros, consulte Introdução aos programas Q# e VS Code às etapas para compilar seu programa e conectar-se ao seu espaço de trabalho Azure Quantum.

Este exemplo tem a seguinte estrutura de diretório:

  • Teleportation_project
    • qsharp.json
    • src
      • Main.qs
      • TeleportOperações
        • TeleportLib.qs
        • PrepareState
          • PrepareStateLib.qs

O arquivo de manifesto contém os campos author e license :

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

Q# Arquivos de origem

O arquivo principal, nomeado 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);
        }
    }

O arquivo TeleportLib.qs define a operação Teleport e chama a operação PrepareBellPair do arquivo 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 PrepareStateLib.qs arquivo 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);
    }

Executar os programas

Escolha a guia para o ambiente onde você executa seu programa.

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

Definir Q# projetos como dependências externas

Você pode configurar Q# projetos como dependências externas para outros projetos, semelhantes a uma biblioteca. As funções e as 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 ser publicada em um repositório público do GitHub.

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

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

Configurar os arquivos de manifesto

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

O arquivo de manifesto do projeto de chamada

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

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

No arquivo de manifesto anterior, MyDependency é uma cadeia de caracteres definida pelo usuário que identifica o namespace quando você chama uma operação. Por exemplo, se você criar uma dependência chamada MyMathFunctions, poderá chamar 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, use o seguinte arquivo de manifesto de exemplo:

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

Observação

Para dependências do GitHub, ref refere-se a um refspec do GitHub. Microsoft recomenda que você sempre use um hash de confirmação para poder contar com uma versão específica de sua dependência.

O arquivo de manifesto do projeto externo

Se o projeto externo Q# for publicado em um repositório público do GitHub, você deverá adicionar a propriedade de arquivos 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 de arquivos é opcional para um projeto externo importado por meio "path" (ou seja, uma importação local baseada em filepath). A propriedade de arquivos é necessária apenas para projetos publicados no GitHub.

Utilize a instrução export

Para tornar funções e operações em um projeto externo acessíveis aos projetos que o chamam, use a declaração export. Você pode exportar qualquer um ou todos os chamáveis no arquivo. Não há suporte para sintaxe de curinga, portanto, você deve especificar cada callable que deseja exportar.

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;

Utilize a instrução import

Para disponibilizar itens de uma dependência externa, use import declarações do programa chamador. A instrução import usa o namespace definido para a dependência no arquivo de manifesto.

Por exemplo, considere a dependência no seguinte arquivo de manifesto:

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

Importe os callables com o seguinte código:

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

...

A import declaração também dá suporte à sintaxe curinga e apelidos.

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

Observação

A instrução usada open atualmente em Q#, que é usada para fazer referência a bibliotecas e namespaces, ainda é suportada, mas será descontinuada eventualmente. Enquanto isso, você pode atualizar opcionalmente seus arquivos atuais para usar a import instrução. Por exemplo, open Std.Diagnostics; pode ser substituído por import Std.Diagnostics.*;.

Exemplo de projeto externo

Para este exemplo, você usa o mesmo programa de teletransporte que o exemplo anterior, mas separa o programa de chamada e os callables em projetos diferentes.

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

  2. Crie um Q# projeto em cada pasta. Para obter detalhes, consulte as etapas em Como criar um Q# projeto.

  3. No programa de chamada Project_A, copie o seguinte código para o arquivo de manifesto, mas edite o caminho conforme necessário para Project_B:

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

    Observação

    Observe que a operação PrepareBellPair não precisa ser exportada porque ela não é chamada diretamente do seu programa em Project_A. Como PrepareBellPair está no escopo local de Project_B, ele já está acessível pela Teleport operação.

  6. Para executar o programa, abra /Project_A/Main.qsVS Code e escolha Executar.

Projetos e namespaces implícitos

Em Q# projetos, se um namespace não for especificado em um .qs programa, o compilador usará o nome do arquivo como o namespace. Em seguida, quando você faz referência a um callable de uma dependência externa, usa a sintaxe <dependencyName>.<namespace>.<callable>. No entanto, se o arquivo for nomeado Main.qs, o compilador assumirá que o namespace e a sintaxe de chamada serão <dependencyName>.<callable>, como no exemplo anterior, import MyTeleportLib.Teleport.

Como você pode ter vários arquivos de projeto, é necessário considerar a sintaxe correta quando fizer referência a callables. Por exemplo, considere um projeto com a seguinte estrutura de arquivos:

  • /Src
    • Main.qs
    • MathFunctions.qs

O código a seguir faz chamadas para a dependência externa:

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 do usuário.