Udostępnij za pośrednictwem


Jak tworzyć projekty i biblioteki niestandardowe oraz zarządzać nimi Q#

W tym artykule dowiesz się, jak tworzyć i udostępniać projekty oraz zarządzać nimiQ#. Q# projekty to struktury folderów z wieloma Q# plikami, które mogą uzyskiwać dostęp do siebie operacji i funkcji. Projekty są przydatne do logicznego organizowania kodu źródłowego. Można również używać projektów jako bibliotek niestandardowych, do których można uzyskiwać dostęp ze źródeł zewnętrznych.

Wymagania wstępne

  • Obszar roboczy usługi Azure Quantum w ramach subskrypcji platformy Azure. Aby utworzyć obszar roboczy, zobacz Tworzenie obszaru roboczego usługi Azure Quantum.
  • Program Visual Studio Code z zainstalowanym rozszerzeniem Platformy Azure Quantum Development Kit i języka Python .
  • Konto usługi GitHub, jeśli planujesz opublikować projekt zewnętrzny w publicznym repozytorium GitHub.

Do uruchamiania programów w języku Python potrzebne są również następujące elementy:

  • Środowisko języka Python z zainstalowanym językiem Python i programem .
  • Usługa Azure Quantum qsharp i azure-quantum pakiety.

Jak Q# działają projekty

Q# Projekt zawiera plik manifestu Q# o nazwie qsharp.json i co najmniej jeden plik *.qs w określonej strukturze folderów. Gdy użytkownik otworzy plik *.qs w programie VS Code lub ustawi project_root element w pliku Jupyter Notebook lub Python, kompilator przeszukuje otaczającą hierarchię folderów dla pliku manifestu i określa zakres projektu. Jeśli plik manifestu nie zostanie znaleziony, kompilator działa w trybie pojedynczego pliku. Projekt można utworzyć Q# ręcznie lub bezpośrednio w programie VS Code.

Projekt zewnętrzny Q# to standardowy Q# projekt, który znajduje się w innym katalogu lub w publicznym repozytorium GitHub i działa jako biblioteka niestandardowa. Projekt zewnętrzny używa export instrukcji do zdefiniowania, do których funkcji i operacji można uzyskiwać dostęp za pomocą programów zewnętrznych. Programy definiują projekt zewnętrzny jako zależność w pliku manifestu i używają import instrukcji w celu uzyskania dostępu do elementów (operacji, funkcji, struktur i przestrzeni nazw) w projekcie zewnętrznym. Aby uzyskać więcej informacji, zobacz Używanie projektów jako zależności zewnętrznych.

Definiowanie Q# projektu

Projekt Q# jest definiowany przez obecność pliku manifestu o nazwie qsharp.json i folderu src (który zawiera Q# pliki źródłowe), z których oba muszą znajdować się w folderze głównym projektu. W przypadku Q# programów i projektów Q# zewnętrznych kompilator automatycznie wykrywa folder projektu. W przypadku programów języka Python i notesów Jupyter Notebook należy określić Q# folder projektu z wywołaniem qsharp.init . Jednak struktura folderów dla Q# projektu pozostaje taka sama dla wszystkich typów programów.

Struktura folderów i hierarchia Q# projektu.

Definiowanie folderu projektu (Q# programy)

Po otwarciu pliku *.qs w programie VS Code Q# kompilator wyszukuje w górę strukturę folderów dla pliku manifestu. Jeśli znajdzie plik manifestu, kompilator zawiera wszystkie Q# pliki w katalogu /src lub dowolnym z jego podkatalogów. Elementy każdego pliku są udostępniane wszystkim innym plikom w projekcie.

Na przykład biorąc pod uwagę tę strukturę folderów:

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

po otwarciu pliku /src/TeleportOperation/PrepareState/PrepareStateLib.qsQ# kompilator:

  1. Sprawdza /src/TeleportOperation/PrepareState/ dla qsharp.json.
  2. Sprawdza /src/TeleportOperation dla qsharp.json.
  3. Sprawdza /src pod kątem qsharp.json.
  4. Sprawdza / qsharp.json.
  5. / Ustanawia jako katalog główny projektu i zawiera wszystkie pliki *.qs w katalogu głównym w projekcie zgodnie z ustawieniami pliku manifestu.

Tworzenie pliku manifestu

Plik manifestu to prosty plik .json o nazwie qsharp.json , który opcjonalnie może zawierać pola autorów, licencji i lints . Minimalny realny plik manifestu to ciąg {}. Podczas tworzenia Q# projektu w programie VS Code zostanie utworzony minimalny plik manifestu.

{}

Przykłady plików manifestu

Poniżej przedstawiono kilka przykładów sposobu, w jaki pliki manifestu mogą definiować zakres Q# projektu.

  • W tym przykładzie autor jest jedynym określonym polem i dlatego wszystkie pliki *.qs w tym katalogu i wszystkie jego podkatalogi są uwzględnione w projekcie Q# .

    {
        "author":"Microsoft",
        "license": "MIT"
    }
    
  • W projekcie Q# można również użyć pliku manifestu, aby dostosować ustawienia linter programu VS Code Q# . Domyślnie trzy reguły lintera to:

    • needlessParens: default = allow

    • divisionByZero: default = warn

    • redundantSemicolons: default = warn

      Za pomocą pliku manifestu można ustawić każdą regułę na allow, warnlub error, na przykład

      {
          "author":"Microsoft",
          "lints": [
              {
                "lint": "needlessParens",
                "level": "allow"
              },
              {
                "lint": "redundantSemicolons",
                "level": "warn"
              },
              {
                "lint": "divisionByZero",
                "level": "error"
              }
            ]
      }
      
  • Możesz również użyć pliku manifestu, aby zdefiniować projekt zewnętrzny Q# jako zależność i operacje dostępu zdalnego i funkcje w tym projekcie zewnętrznym. Aby uzyskać więcej informacji, zobacz Używanie projektów jako zależności zewnętrznych.

Q# wymagania i właściwości projektu

Następujące wymagania i konfiguracje mają zastosowanie do wszystkich Q# projektów.

  • Wszystkie pliki *.qs, które chcesz uwzględnić w projekcie, muszą znajdować się w folderze o nazwie src, który musi znajdować się w folderze głównym folderu Q#. Podczas tworzenia Q# projektu w programie VS Code /src folder jest tworzony automatycznie.

  • Plik manifestu powinien być na tym samym poziomie co folder src . Podczas tworzenia Q# projektu w programie VS Code jest tworzony automatycznie minimalny plik.

  • Instrukcje służą import do odwołwania się do operacji i funkcji z innych plików w projekcie.

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

    lub odwoływanie się do nich indywidualnie z przestrzenią nazw

    MyMathLib.Multiply(x,y);  
    

Tylko w przypadku Q# projektów

  • Tylko jeden plik *.qs w projekcie Q# może mieć zdefiniowany punkt wejścia zdefiniowany przez jedną Main() operację.
  • Plik *.qs z definicją punktu wejścia może znajdować się na dowolnym poziomie poniżej pliku manifestu.
  • Każda operacja lub funkcja buforowana z pliku *.qs w dowolnym miejscu projektu Q# jest wyświetlana w tekście predykcyjnym w programie VS Code.
  • Jeśli przestrzeń nazw dla wybranej operacji lub funkcji nie jest jeszcze importowana, program VS Code automatycznie dodaje niezbędną import instrukcję.

Kroki tworzenia Q# projektu

Te kroki dotyczą wszystkich Q# projektów.

  1. W Eksploratorze plików programu VS Code kliknij prawym przyciskiem myszy folder, którego chcesz użyć dla folderu Q# głównego projektu, a następnie wybierz polecenie Utwórz Q# projekt lub otwórz folder i wybierz polecenie Wyświetl > paletę >Q#Q# poleceń: Utwórz projekt....

  2. Program VS Code tworzy minimalny plik manifestu w folderze i dodaje /src folder z plikiem szablonu Main.qs .

  3. Edytuj plik manifestu zgodnie z potrzebami. Zobacz Przykłady plików manifestu.

  4. Dodaj i organizuj Q# pliki źródłowe w folderze /src .

  5. Jeśli uzyskujesz dostęp do Q# projektu z poziomu programu w języku Python lub notesu Jupyter Notebook, ustaw ścieżkę folderu głównego przy użyciu polecenia qsharp.init. W tym przykładzie przyjęto założenie, że program znajduje się w folderze Q# /src projektu:

    qsharp.init(project_root = '../Teleportation_project')
    
  6. Jeśli używasz tylko Q# plików w programie VS Code, podczas otwierania Q# pliku kompilator wyszukuje plik manifestu, określa folder główny projektu, a następnie skanuje podfolder plików *.qs.

Uwaga

Możesz również ręcznie utworzyć plik manifestu /src i folder w kroku 2.

Przykładowy projekt

Ten program teleportacji kwantowej jest przykładem Q# projektu opartego na przedstawionej wcześniej strukturze pojedynczego folderu i działa w symulatorze lokalnym w programie VS Code. Aby uruchomić program na sprzęcie azure Quantum lub symulatorach innych firm, zobacz Rozpoczynanie pracy z programami Q# i programem VSCode, aby uzyskać instrukcje kompilowania programu i nawiązywania połączenia z obszarem roboczym platformy Azure.

W przykładzie użyto tej struktury katalogów:

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

Plik manifestu zawiera pola autorów i licencji:

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

Q# pliki źródłowe

Główny plik Main.qs zawiera punkt wejścia i odwołuje się TeleportOperations.TeleportLib do przestrzeni nazw z pliku 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 definiuje operację Teleport() i wywołuje operację PrepareBellPair() z pliku 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);
    }

Plik PrepareStateLib.qs zawiera standardową operację wielokrotnego użytku w celu utworzenia pary bell.

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

Uruchamianie programów

Wybierz kartę środowiska, w którym jest uruchomiony program.

Aby uruchomić ten program, otwórz plik Main.qs w programie VS Code i wybierz pozycję Uruchom.

Konfigurowanie Q# projektów jako zależności zewnętrznych

Projekt Q# można również skonfigurować jako zależność zewnętrzną dla innych projektów, działając podobnie jak biblioteka, w której funkcje i operacje w projekcie zewnętrznym Q# są udostępniane wielu Q# projektom. Zależność zewnętrzna może znajdować się w udziale dysku lub opublikowanym w publicznym repozytorium GitHub.

Aby użyć Q# projektu jako zależności zewnętrznej, musisz:

  • Dodaj projekt zewnętrzny jako zależność w pliku manifestu projektu wywołującego.
  • Jeśli projekt zewnętrzny zostanie opublikowany w usłudze GitHub, dodaj właściwość "files" do pliku manifestu projektu zewnętrznego.
  • Dodaj export instrukcje do projektu zewnętrznego.
  • Dodaj import instrukcje do projektu wywołującego.

Konfigurowanie plików manifestu

Projekty zewnętrzne Q# mogą znajdować się w udziale dysku lokalnym lub sieciowym albo publikować je w publicznym repozytorium GitHub.

Plik manifestu projektu wywołującego

Aby dodać zależność do projektu zewnętrznego w udziale dysku, zdefiniuj zależność w pliku manifestu projektu wywołującego.

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

gdzie "MyDependency" to ciąg zdefiniowany przez użytkownika, który identyfikuje przestrzeń nazw podczas wywoływania operacji. Jeśli na przykład utworzysz zależność o nazwie "MyMathFunctions", wywołasz funkcję z tej zależności za pomocą polecenia MyMathFunctions.MyFunction().

Aby dodać zależność do projektu opublikowanego w publicznym repozytorium GitHub

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

Uwaga

W przypadku zależności usługi GitHub "ref" odnosi się do refspec usługi GitHub. Firma Microsoft zaleca zawsze używanie skrótu zatwierdzenia, dzięki czemu można polegać na określonej wersji zależności.

Plik manifestu projektu zewnętrznego

Jeśli projekt zewnętrzny Q# jest publikowany w publicznym repozytorium GitHub, musisz dodać właściwość files do pliku manifestu projektu zewnętrznego, w tym wszystkie pliki używane w projekcie.

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

Właściwość "files" jest opcjonalna dla projektu zewnętrznego importowanego za pośrednictwem "path" (czyli lokalnego importu opartego na ścieżce plików). Jest to wymagane tylko w przypadku projektów publikowanych w usłudze GitHub.

Korzystanie z instrukcji export

Aby udostępnić funkcje i operacje w projekcie zewnętrznym do wywoływania projektów, należy użyć instrukcji export . W pliku można wyeksportować dowolne lub wszystkie obiekty wywołujące. Składnia symboli wieloznacznego nie jest obsługiwana. Należy określić każdą wywołalną do wyeksportowania.

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;             

Używanie instrukcji import

Z poziomu programu wywołującego używa import się instrukcji do udostępniania elementów z zależności zewnętrznej. import instrukcje używają przestrzeni nazw zdefiniowanej dla zależności w pliku manifestu. Na przykład dla tej zależności

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

importowane możliwie wywołania jako

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

Instrukcja import obsługuje również składnię symboli wieloznacznego i aliasy

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

Uwaga

Obecnie używana open instrukcja w Q#pliku , która jest używana do odwołzania się do bibliotek i przestrzeni nazw, jest nadal obsługiwana, ale ostatecznie zostanie wycofana. W międzyczasie możesz opcjonalnie zaktualizować bieżące pliki, aby użyć instrukcji import . Na przykład open Microsoft.Quantum.Diagnostics; można zastąpić ciągiem import Microsoft.Quantum.Diagnostics.*;. Należy również pamiętać, że w przypadku używania instrukcji import z bibliotekami standardowymi Q# można skrócić przestrzeń nazw katalogu głównego do Std. Można na przykład import Microsoft.Quantum.Diagnostics.*; zapisać jako import Std.Diagnostics.*;.

Przykładowy projekt zewnętrzny

W tym przykładzie użyjesz tego samego programu teleportacji co w poprzednim przykładzie, ale oddzielisz program wywołujący i obiekty wywołujące do różnych projektów.

  1. Utwórz dwa foldery na dysku lokalnym, na przykład "Project_A" i "Project_B".

  2. Q# Utwórz projekt w każdym folderze, wykonując kroki opisane w temacie Kroki tworzenia Q# projektu.

  3. W Project_A program wywołujący skopiuj następujący kod do pliku manifestu, edytując ścieżkę zgodnie z potrzebami Project_B

    {
      "author": "Microsoft",
      "license": "MIT",
      "dependencies": {
        "MyTeleportLib": {
          "path": "/Project_B" 
          }
        }
      }    
    
  4. W Project_A skopiuj następujący kod do pliku 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. W Project_B skopiuj następujący kod do pliku 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
    

    Uwaga

    Należy pamiętać, że operacja nie musi być eksportowana, PrepareBellPair ponieważ nie jest wywoływana bezpośrednio z programu w Project_A. Ponieważ znajduje się on w lokalnym zakresie Project_B, jest już dostępny przez operację Teleport

  6. Aby uruchomić program, otwórz plik /Project_A/Main.qs w programie VS Code i wybierz pozycję Uruchom.

Projekty i niejawne przestrzenie nazw

Jeśli Q# w projektach nie określono przestrzeni nazw w programie *.qs, kompilator używa nazwy pliku jako przestrzeni nazw. Odwoływanie się do wywołania z zależności zewnętrznej używa składni dependencyName<>.<przestrzeń nazw>.<z możliwością wywołania>. Jeśli jednak plik nosi nazwę "Main.qs", kompilator zakłada przestrzeń nazw, a składnia wywołująca to <dependencyName>.<wywoływane>, tak jak w poprzednim przykładzie, import MyTeleportLib.Teleport.

Ponieważ nie jest rzadkością mieć wiele plików projektu, należy uwzględnić poprawną składnię podczas odwoływania się do elementów wywołujących. Na przykład w projekcie z następującą strukturą plików

  • /Src
    • Main.qs
    • MathFunctions.qs

wywołania zależności zewnętrznej byłyby następujące

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

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

Aby uzyskać więcej informacji na temat zachowania przestrzeni nazw, zobacz Przestrzenie nazw użytkowników.