Partilhar 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 seu 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 Python ambiente com Python e Pip instalados.

  • A biblioteca qdkPython com o azure extra opcional.

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

Como Q# funcionam os projetos

Um Q# projeto contém um Q# arquivo de manifesto, chamado qsharp.json, e um ou mais .qs arquivos em uma estrutura de pastas especificada. Você pode criar um Q# projeto manualmente ou diretamente no VS Code.

Quando você abre um .qs arquivo no VS Code, 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.

Quando 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 operações que são 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, estruturas 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, chamado qsharp.json, e uma src pasta, ambos devem estar na pasta raiz do projeto. A src pasta contém os ficheiros de Q# origem. Para Q# programas e projetos externos, o Q# compilador deteta a pasta do projeto automaticamente. Para Python programas e Jupyter Notebook arquivos, você deve especificar a pasta do Q# projeto com uma qsharp.init chamada. No entanto, a estrutura de pastas para um Q# projeto é a mesma para todos os tipos de programas.

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

Definir a pasta do projeto (Q# programas)

Quando abre um arquivo .qs no VS Code, o compilador Q# procura por um ficheiro de manifesto na estrutura de pastas acima. Se o compilador encontrar um ficheiro de manifesto, então o compilador inclui todos os arquivos Q# no diretório /src e de todos os seus subdiretórios. 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:

  • Projeto_de_Teletransporte
    • 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 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 .qs arquivos 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 JSON nomeado qsharp.json que pode, opcionalmente, incluir campos autor, licença e lints . 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

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

  • Neste exemplo, 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 de 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 seguintes requisitos e configurações aplicam-se a todos os Q# projetos.

  • Todos os .qs arquivos que você deseja incluir no projeto devem estar sob uma pasta chamada src, que deve estar sob a Q# pasta raiz do projeto. 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 src pasta. 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 faça referência a eles individualmente com o namespace.

    MyMathLib.Multiply(x,y); 
    

Para projetos Q# apenas

  • Você pode definir uma operação de ponto de entrada em apenas um arquivo .qs em um projeto Q#, sendo essa a operação padrão Main().
  • Você deve colocar o arquivo .qs com a definição do ponto de entrada em um nível de diretório abaixo do arquivo de manifesto do projeto.
  • Todas as operações e funções que são armazenadas em cache no projeto Q# a partir de uma exibição .qs em texto preditivo no VS Code.
  • Se o namespace para uma operação ou função selecionada ainda não for importado, 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 de VS Code arquivos, vá para a pasta que você deseja usar como a pasta raiz para o Q# projeto.

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

  3. Digite QDK: Criar Q# projeto e pressione Enter. VS Code Cria um arquivo de manifesto mínimo na pasta e adiciona uma /src pasta com um arquivo de Main.qs modelo.

  4. Edite o arquivo de manifesto para seu projeto. Consulte Exemplos de ficheiro Manifesto.

  5. Adicione e organize os seus Q# ficheiros fonte na pasta /src.

  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 estiver a usar apenas os ficheiros Q# em VS Code, o compilador procura um ficheiro de manifesto quando abrir um ficheiro Q#, determinando a pasta raiz do projeto e em seguida, verifica a subpasta em busca de ficheiros .qs.

Nota

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

Exemplo de projeto

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

Este exemplo tem a seguinte estrutura de diretórios:

  • Projeto_de_Teletransporte
    • 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, chamado 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 a partir 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 em que você executa o programa.

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

Configurar Q# projetos como dependências externas

Você pode configurar Q# projetos como dependências externas para outros projetos, semelhante a uma biblioteca. As funções e operações no projeto externo Q# são disponibilizadas para vários Q# projetos. Uma dependência externa pode residir numa partilha de unidade ou ser publicada num repositório público no 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 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.

Configurar os arquivos de manifesto

Projetos externos Q# podem residir em um compartilhamento de unidade local ou de rede 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 uma partilha de disco, defina a dependência no arquivo de manifesto do projeto solicitante.

{
    "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"
            }
        }
    }
}

Nota

Para dependências do GitHub, ref refere-se a uma refspec do GitHub. Microsoft recomenda que você sempre use um hash de confirmação para que possa confiar em uma versão específica da 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 importado via "path" (ou seja, uma importação local baseada em caminho de arquivo). A propriedade files é necessária apenas para projetos publicados no GitHub.

Use a instrução export

Para tornar funções e operações num projeto externo acessíveis aos projetos que as chamam, use a export instrução. Você pode exportar qualquer um ou todos os chamáveis no arquivo. A sintaxe curinga não é suportada, portanto, deves especificar cada função que desejas 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;

Use a instrução import

Para disponibilizar itens de uma dependência externa, use instruções do import do programa de origem. A instrução import usa o namespace definido para a dependência no ficheiro 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 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 atualmente usada open no Q#, que é utilizada para fazer referência a bibliotecas e namespaces, ainda é suportada, mas será preterida no futuro. Enquanto isso, você pode, opcionalmente, atualizar 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

Neste exemplo, utiliza o mesmo programa de teletransporte do exemplo anterior, mas separa o programa que faz a chamada e os chamáveis em projetos diferentes.

  1. Crie duas pastas na 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 Project_A em execução, copie o seguinte código no arquivo de manifesto, mas edite o caminho conforme necessário para o 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 PrepareBellPair estar no âmbito local do Project_B, ele já está acessível pela Teleport operação.

  6. Para executar o programa, abra /Project_A/Main.qs e VS Code 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 namespace. Em seguida, quando você faz referência a um chamável de uma dependência externa, você 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 são <dependencyName>.<callable>, como no exemplo anterior, import MyTeleportLib.Teleport.

Como poderá ter vários ficheiros de projeto, precisa ter em conta a sintaxe correta ao referenciar elementos chamáveis. Por exemplo, considere um projeto com a seguinte estrutura de arquivo:

  • /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 espaço de nomes, consulte Espaços de nomes de utilizador.