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. Também podes usar projetos como bibliotecas personalizadas a que podes aceder a partir de fontes externas.

Pré-requisitos

Para executar programas Python, também precisa de:

  • Um ambiente Python com Python e Pip instalados.

  • A biblioteca qdkPython com o extra azure.

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

Como Q# funcionam os projetos

Um Q# projeto contém um Q# ficheiro manifesto chamado qsharp.json, e um ou mais .qs e .qsc ficheiros numa estrutura de pastas especificada. Você pode criar um Q# projeto manualmente ou diretamente no VS Code.

Quando abres um .qs ficheiro ou .qsc em VS Code, o compilador pesquisa a hierarquia de pastas circundante para o ficheiro manifest e determina o âmbito do projeto. Se o compilador não encontrar um ficheiro manifesto, então o compilador opera em modo de ficheiro único.

Quando defines o ficheiro project_root num ficheiro Jupyter Notebook ou Python, o compilador procura o ficheiro manifest na pasta project_root.

Um projeto externo Q# é um projeto padrão Q# localizado noutro diretório ou num repositório público de GitHub, e funciona 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 qsharp.json ficheiro manifesto e de 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 automaticamente a pasta do projeto. Para programas Python e ficheiros Jupyter Notebook, deve especificar a pasta do Q# projeto com uma chamada de qsharp.init. 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.

Defina a pasta do projeto para 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 manifesto, então inclui todos os Q# ficheiros do /src diretório e dos 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 /Teleportation_project à procura de qsharp.json e encontra o ficheiro.
  5. Estabelece /Teleportation_project como o diretório raiz do projeto e inclui todos os ficheiros .qs e .qsc sob o diretório /src do projeto. Se o ficheiro de manifestos.

Nota

Se incluir referências explícitas aos caminhos de ficheiro .qs e .qsc em qsharp.json, o compilador carrega esses ficheiros e não passa pelo processo de descoberta automática. Referências explícitas a caminhos de ficheiros só são necessárias quando defines uma biblioteca como carregável a partir de uma referência Git.

Criar um arquivo de manifesto

Um ficheiro manifesto é um ficheiro JSON nomeado qsharp.json que pode incluir campos opcionais author, license, 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 seguintes mostram como os ficheiros manifestos definem o âmbito do seu Q# projeto.

  • Neste exemplo, author é o único campo especificado, por isso todos .qs os ficheiros deste diretório e dos seus subdiretórios estão incluídos no Q# projeto.

    {
        "author":"Microsoft"
    }
    
  • 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 crias um Q# projeto em VS Code, um ficheiro de manifesto mínimo é automaticamente criado.

  • 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. Introduzir QDK: Criar Q# projeto. 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 estiveres a aceder ao projeto Q# a partir de um programa Python ou Jupyter Notebook, então define o caminho da pasta root com qsharp.init. Este exemplo pressupõe que seu /src programa esteja na pasta do Q# projeto:

    qsharp.init(project_root = '../Teleportation_project')
    
  7. Se estiveres a usar apenas ficheiros Q# em VS Code, o compilador procura um ficheiro manifesto quando abres um ficheiro Q# e determina a pasta raiz do projeto. Depois, o compilador procura /src e os seus subdiretórios para ficheiros .qs e .qsc.

Nota

Podes criar manualmente o ficheiro manifesto e a /src pasta em vez disso.

Exemplo de projeto

Este programa de teletransporte quântico é um exemplo de um projeto Q# que corre no simulador local em VS Code. Para correr o programa em hardware Azure Quantum ou simuladores de terceiros, consulte Comece com os programas Q# e VS Code para os passos de compilação do seu programa e ligação ao seu espaço de trabalho Azure Quantum.

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 ficheiro Main.qs principal 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 ficheiro TeleportLib.qs define a operação Teleport e chama a operação PrepareBellPair a partir do ficheiro 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

Selecione o separador correspondente ao ambiente onde executa o seu programa.

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

Configurar Q# projetos como dependências externas

Pode configurar Q# projetos como uma dependência externa para outros projetos, semelhante a uma biblioteca, para tornar funções e operações no projeto externo Q# disponíveis para outros Q# projetos. Uma dependência externa pode residir numa partilha de disco ou ser publicada num 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 chamador.
  • Se o projeto externo for publicado para GitHub, então adicione a propriedade files ao ficheiro 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 numa partilha de disco local ou de rede, ou pode publicá-los num repositório público de 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 ficheiro manifest anterior, MyDependency existe uma cadeia definida pelo utilizador que identifica o namespace quando 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 num repositório público do GitHub, use o seguinte ficheiro 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 um 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 o seu projeto externo Q# for publicado num repositório público de GitHub, então deve adicionar a propriedade files ao ficheiro manifesto do projeto externo, incluindo todos os ficheiros que o projeto utiliza.

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

A files propriedade é opcional para um projeto externo que você importa "path" através de uma importação baseada num caminho de ficheiro local. A propriedade files é exigida apenas para projetos publicados para 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. Não é possível usar a sintaxe wildcard, por isso deve especificar cada função 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;

Use a instrução import

Para disponibilizar itens de uma dependência externa, use instruções do import do programa de origem. A import instrução usa o namespace que defines para a dependência no ficheiro manifest.

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; 

Exemplo de projeto externo

Para este exemplo, use o mesmo programa de teletransporte do exemplo anterior, mas separe o programa de invocação 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

    Não precisas de exportar a operação PrepareBellPair se o teu programa em Project_A não chamar diretamente essa operação. A operação PrepareBellPair já é acessível pela operação Teleport porque PrepareBellPair está no âmbito local de Project_B.

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

Projetos e namespaces implícitos

Nos Q# projetos, se não especificares um namespace num .qs programa, então o compilador usa o nome do ficheiro 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 ficheiro for nomeado Main.qs, então o compilador assume que o espaço de nomes e a sintaxe de chamada são <dependencyName>.<callable>. Por exemplo, 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.