Come usare i Q# progetti

Con Azure Quantum Development Kitè possibile definire Q# progetti, ovvero strutture di cartelle con più Q# file che possono accedere tra loro operazioni e funzioni. I progetti sono utili per organizzare logicamente il codice sorgente. È anche possibile usare progetti come dipendenze esterne o librerie personalizzate a cui è possibile accedere da origini esterne.

Un Q# progetto contiene un Q# file manifesto, denominato qsharp.json e uno o più file *.qs in una struttura di cartelle specificata. Quando un utente apre un file *.qs in VS Code o imposta project_root in un file Jupyter Notebook o Python, il compilatore cerca il file manifesto nella gerarchia di cartelle circostanti e determina l'ambito del progetto. Se non viene trovato alcun file manifesto, il compilatore opera in una singola modalità file. Un Q# progetto può essere creato manualmente o direttamente in VS Code.

Un progetto esterno Q# è un progetto standard Q# che risiede in un'altra directory o in un repository GitHub pubblico e usa istruzioni export per definire le funzioni e le operazioni a cui è possibile accedere da programmi esterni. I programmi definiscono il progetto esterno come dipendenza nel file manifesto e usano import istruzioni per accedere agli elementi (operazioni, funzioni, struct e spazi dei nomi) nel progetto esterno. Per altre informazioni, vedere Uso di progetti come dipendenze esterne.

Prerequisiti

Per l'esecuzione di programmi Python, è anche necessario:

  • Un ambiente Python con Python e Pip installati.
  • Azure Quantum qsharp e azure-quantum i pacchetti.

Definire un Q# progetto

Un Q# progetto è definito dalla presenza di un file manifesto, denominato qsharp.json, e una cartella src (che contiene i Q# file di origine), entrambi devono trovarsi nella cartella radice del progetto. Per Q# i programmi e i progetti esterni, il Q# compilatore rileva automaticamente la cartella del progetto. Per i programmi Python e Jupyter Notebook, è necessario specificare la cartella del Q# progetto con una qsharp.init chiamata. La struttura di cartelle per un Q# progetto rimane tuttavia la stessa per tutti i tipi di programmi.

Immagine che mostra la gerarchia di cartelle per un Q# progetto.

Definizione della cartella del progetto (Q# programmi)

Quando un file *.qs viene aperto in VS Code, il Q# compilatore cerca verso l'alto nella struttura di cartelle un file manifesto. Se trova un file manifesto, il compilatore include tutti i Q# file nella directory /src o in una delle relative sottodirectory. Gli elementi di ogni file vengono resi disponibili per tutti gli altri file all'interno del progetto.

Ad esempio, data questa struttura di cartelle:

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

quando si apre il file /src/TeleportOperation/PrepareState/PrepareStateLib.qs, il Q# compilatore:

  1. Controlla /src/TeleportOperation/PrepareState/ per qsharp.json.
  2. Controlla /src/TeleportOperation per qsharp.json.
  3. Controlla /src per qsharp.json.
  4. Verifica la presenza di / qsharp.json.
  5. / Stabilisce come directory radice del progetto e include tutti i file *.qs nella radice del progetto, in base alle impostazioni del file manifesto.

Creare un file manifesto

Un file manifesto è un semplice file .json denominato qsharp.json che può includere facoltativamente campi autore, licenza e lints . Il file manifesto minimo praticabile è la stringa {}. Quando si crea un Q# progetto in VS Code, viene creato automaticamente un file manifesto minimo.

{}

Esempi di file manifesto

Di seguito sono riportati alcuni esempi di come i file manifesto possono definire l'ambito del Q# progetto.

  • In questo esempio, author è l'unico campo specificato e quindi tutti i file *.qs in questa directory e tutte le relative sottodirectory sono incluse nel Q# progetto.

    {
        "author":"Microsoft",
        "license": "MIT"
    }
    
  • All'interno di un Q# progetto, è anche possibile usare il file manifesto per ottimizzare le impostazioni Linter di VS Code Q# . Per impostazione predefinita, le tre regole Linter sono:

    • needlessParens: default = allow
    • divisionByZero: default = warn
    • redundantSemicolons: default = warn

    Usando il file manifesto, è possibile impostare ogni regola su allow, warno error, ad esempio

    {
        "author":"Microsoft",
        "lints": [
            {
              "lint": "needlessParens",
              "level": "allow"
            },
            {
              "lint": "redundantSemicolons",
              "level": "warn"
            },
            {
              "lint": "divisionByZero",
              "level": "error"
            }
          ]
    }
    
  • È anche possibile usare il file manifesto per definire un progetto esterno Q# come dipendenza e accedere in remoto a operazioni e funzioni in tale progetto esterno. Per altre informazioni, vedere Uso di progetti come dipendenze esterne.

Q# requisiti e proprietà del progetto

I requisiti e le configurazioni seguenti si applicano a tutti i Q# progetti.

  • Tutti i file *.qs che si desidera includere nel progetto devono trovarsi in una cartella denominata src, che deve trovarsi nella cartella radice di Q#. Quando si crea un Q# progetto in VS Code, la /src cartella viene creata automaticamente.

  • Il file manifesto deve essere allo stesso livello della cartella src . Quando si crea un Q# progetto in VS Code, viene creato automaticamente un file minimo.

  • Usare import istruzioni per fare riferimento a operazioni e funzioni di altri file nel progetto.

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

    o farvi riferimento singolarmente con lo spazio dei nomi

    MyMathLib.Multiply(x,y);  
    

Solo per Q# i progetti

  • Un solo file *.qs in un Q# progetto può avere un punto di ingresso definito, definito da una singola Main() operazione.
  • Il file *.qs con la definizione del punto di ingresso può trovarsi a qualsiasi livello al di sotto del file manifesto.
  • Qualsiasi operazione o funzione memorizzata nella cache da un file *.qs in qualsiasi punto del Q# progetto viene visualizzata nel testo predittivo in VS Code.
  • Se lo spazio dei nomi per un'operazione o una funzione selezionata non è ancora importato, VS Code aggiunge automaticamente l'istruzione necessaria import .

Passaggi per la creazione di un Q# progetto

Questi passaggi si applicano a tutti i Q# progetti.

  1. In Esplora file di VS Code fare clic con il pulsante destro del mouse sulla cartella che si vuole usare per la cartella radice del Q# progetto e selezionare Crea Q# progetto oppure aprire la cartella e selezionare Visualizza > riquadro comandi >Q#: Crea un Q# progetto....

  2. VS Code crea un file manifesto minimo nella cartella e aggiunge una /src cartella con un Main.qs file modello.

  3. Modificare il file manifesto in base alle esigenze. Vedere Esempi di file manifesto.

  4. Aggiungere e organizzare i Q# file di origine nella /src cartella .

  5. Se si accede al Q# progetto da un programma Python o da Jupyter Notebook, impostare il percorso della cartella radice usando qsharp.init. Questo esempio presuppone che il programma si trova nella cartella /src del Q# progetto:

    qsharp.init(project_root = '../Teleportation_project')
    
  6. Se si usano solo Q# file in VS Code, quando si apre un Q# file, il compilatore cerca un file manifesto, determina la cartella radice del progetto e quindi analizza la sottocartella per i file *.qs.

Nota

È anche possibile creare manualmente il file manifesto e la /src cartella nel passaggio 2.

Progetto di esempio

Questo programma di teletrasportazione quantistica è un esempio di progetto Q# basato sulla struttura a cartella singola illustrata in precedenza e viene eseguito nel simulatore locale in VS Code. Per eseguire il programma su hardware Azure Quantum o simulatori di terze parti, vedere Introduzione ai Q# programmi e VSCode per la procedura per compilare il programma e connettersi all'area di lavoro di Azure.

L'esempio usa questa struttura di directory:

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

Il file manifesto contiene i campi autore e licenza :

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

Q# file di origine

Il file principale Main.qs contiene il punto di ingresso e fa riferimento allo TeleportOperations.TeleportLib spazio dei nomi da 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 definisce l'operazione Teleport() e chiama l'operazione PrepareBellPair() da 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);
    }

Il file PrepareStateLib.qs contiene un'operazione riutilizzabile standard per creare una coppia Bell.

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

Esecuzione dei programmi

Selezionare la scheda per l'ambiente in cui si esegue il programma.

Per eseguire questo programma, aprire il file Main.qs in VS Code e selezionare Esegui.

Configurazione di Q# progetti come dipendenze esterne

Un Q# progetto può anche essere configurato come dipendenza esterna per altri progetti, come una libreria, in cui le funzioni e le operazioni nel progetto esterno Q# vengono rese disponibili a più Q# progetti. Una dipendenza esterna può risiedere in una condivisione di unità o pubblicata in un repository GitHub pubblico.

Per usare un Q# progetto come dipendenza esterna, è necessario:

  • Aggiungere il progetto esterno come dipendenza nel file manifesto del progetto chiamante.
  • Se il progetto esterno viene pubblicato in GitHub, aggiungere la proprietà "files" al file manifesto del progetto esterno.
  • Aggiungere export istruzioni al progetto esterno.
  • Aggiungere import istruzioni al progetto chiamante.

Configurazione dei file manifesto

I progetti esterni Q# possono risiedere in una condivisione di unità di rete o locale o pubblicata in un repository GitHub pubblico.

File manifesto del progetto chiamante

Per aggiungere una dipendenza a un progetto esterno in una condivisione di unità, definire la dipendenza nel file manifesto del progetto chiamante.

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

dove "MyDependency" è una stringa definita dall'utente che identifica lo spazio dei nomi quando si chiama un'operazione. Ad esempio, se si crea una dipendenza denominata "MyMathFunctions", si chiamerebbe una funzione da tale dipendenza con MyMathFunctions.MyFunction().

Per aggiungere una dipendenza a un progetto pubblicato in un repository GitHub pubblico

{
    "author": "Microsoft",
    "dependencies": {
        "MyDependency": {
            "github": {
                "owner": "GitHubUser",
                "repo": "GitHubRepoName",
                "ref": "CommitHash",
                "path": "/path/to/dependency"
            }
        }
}
  • Per le dipendenze di GitHub, "ref" fa riferimento a un refspec di GitHub. Microsoft consiglia di usare sempre un hash di commit, in modo da poter fare affidamento su una versione specifica della dipendenza.

File manifesto del progetto esterno

Se il progetto esterno Q# viene pubblicato in un repository GitHub pubblico, è necessario aggiungere la proprietà files al file manifesto del progetto esterno, inclusi tutti i file usati nel progetto.

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

La proprietà "files" è facoltativa per un progetto esterno importato tramite "path" (ovvero un'importazione basata su filepath locale). È necessario solo per i progetti pubblicati in GitHub.

Uso dell'istruzione export

Per rendere accessibili funzioni e operazioni in un progetto esterno per chiamare i progetti, usare l'istruzione export . È possibile esportare uno o tutti i chiamabili nel file. La sintassi con caratteri jolly non è supportata, è necessario specificare ogni chiamata da esportare.

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;             

Uso dell'istruzione import

Dal programma chiamante si usano import istruzioni per rendere disponibili gli elementi da una dipendenza esterna. import Le istruzioni usano lo spazio dei nomi definito per la dipendenza nel file manifesto. Ad esempio, per questa dipendenza

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

si importano callable come

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

L'istruzione import supporta anche la sintassi con caratteri jolly e gli alias

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

L'istruzione attualmente usata in Q#, che viene usata open per fare riferimento a librerie e spazi dei nomi, è ancora supportata, ma verrà deprecata alla fine. Nel frattempo, è possibile aggiornare facoltativamente i file correnti per usare l'istruzione import . Ad esempio, open Microsoft.Quantum.Diagnostics; può essere sostituito da import Microsoft.Quantum.Diagnostics.*;. Si noti anche che quando si usa l'istruzione import con le librerie standard Q# , è possibile abbreviare lo spazio dei nomi radice in Std. Ad esempio, è possibile scrivere import Microsoft.Quantum.Diagnostics.*; nel formato import Std.Diagnostics.*;.

Esempio di progetto esterno

Per questo esempio si userà lo stesso programma di teletrasporto dell'esempio precedente, ma separare il programma chiamante e i chiamabili in progetti diversi.

  1. Creare due cartelle nell'unità locale, ad esempio "Project_A" e "Project_B".

  2. Creare un Q# progetto in ogni cartella seguendo i passaggi descritti in Passaggi per la creazione di un Q# progetto.

  3. In Project_A, il programma chiamante copiare il codice seguente nel file manifesto, modificando il percorso in base alle esigenze per Project_B

    {
      "author": "Microsoft",
      "license": "MIT",
      "dependencies": {
        "MyTeleportLib": {
          "path": "/Project_B" 
          }
        }
      }    
    
  4. In Project_A copiare il codice seguente in 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. In Project_B copiare il codice seguente in 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

    Si noti che l'operazione PrepareBellPair non deve essere esportata perché non viene chiamata direttamente dal programma in Project_A. Poiché si trova nell'ambito locale di Project_B, è già accessibile dall'operazione Teleport .

  6. Per eseguire il programma, aprire /Project_A/Main.qs in VS Code e selezionare Esegui.

Progetti e spazi dei nomi impliciti

Nei Q# progetti, se uno spazio dei nomi non è specificato in un programma *.qs, il compilatore usa il nome file come spazio dei nomi. Facendo riferimento a un oggetto chiamabile da una dipendenza esterna, viene quindi usata la sintassi <dependencyName>.<spazio dei nomi>.<chiamabile>. Tuttavia, se il file è denominato "Main.qs", il compilatore presuppone lo spazio dei nomi e la sintassi chiamante è <dependencyName>.<chiamabile>, come nell'esempio precedente, import MyTeleportLib.Teleport.

Poiché non è insolito avere più file di progetto, è necessario tenere conto della sintassi corretta quando si fa riferimento a callables. Ad esempio, in un progetto con la struttura di file seguente

  • /Src
    • Main.qs
    • MathFunctions.qs

le chiamate alla dipendenza esterna sarebbero

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

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

Per altre informazioni sul comportamento dello spazio dei nomi, vedere Spazi dei nomi utente.