Sviluppare con Q# e programma .NET
Il linguaggio di programmazione Q# è progettato per funzionare anche con i linguaggi .NET, come C# e F#. Questa guida illustra come usare Q# con un programma host scritto in un linguaggio .NET.
Prima di tutto si creano l'applicazione Q# e l'host .NET, quindi eseguire una chiamata a Q# dall'host.
Prerequisito
Configurare l'ambiente .NET con Microsoft Quantum Development Kit seguendo la procedura descritta in Configurare Quantum Development Kit.
Creazione di una libreria Q# e di un host .NET
Il primo passaggio consiste nel creare progetti per la libreria Q# e per l'host .NET che verrà chiamato in operazioni e funzioni definite nella libreria Q#.
Seguire le istruzioni riportate nella scheda corrispondente al proprio ambiente di sviluppo. Se si usa un editor diverso da Visual Studio o VS Code, seguire la procedura per il prompt dei comandi.
Creare una nuova libreria Q#
dotnet new classlib -lang Q# -o quantum
Creare un nuovo progetto console C# o F#
dotnet new console -lang C# -o host
Aggiungere la libreria Q# come riferimento dal programma host
cd host dotnet add reference ../quantum/quantum.csproj
[Facoltativo] Creare una soluzione per entrambi i progetti
dotnet new sln -n quantum-dotnet dotnet sln quantum-dotnet.sln add ./quantum/quantum.csproj dotnet sln quantum-dotnet.sln add ./host/host.csproj
Chiamata in Q# da .NET
Dopo aver configurato i progetti seguendo le istruzioni riportate in precedenza, è possibile eseguire chiamate in Q# dall'applicazione console .NET. Il compilatoreQ# creerà le classi .NET per ogni funzione e operazione Q# che consentono di eseguire i programmi quantistici in un simulatore.
Ad esempio, l'esempio di interoperabilità .NET include l'esempio seguente di un'operazione Q#:
namespace Microsoft.Quantum.Samples {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Measurement;
/// # Summary
/// A quantum oracle which implements the following function:
/// f(x₀, …, xₙ₋₁) = Σᵢ (rᵢ xᵢ + (1 - rᵢ)(1 - xᵢ)) modulo 2 for a given bit vector r = (r₀, …, rₙ₋₁).
///
/// # Input
/// ## r
/// A bit vector of length N
/// ## x
/// N qubits in arbitrary state |x⟩ (input register)
/// ## y
/// A qubit in arbitrary state |y⟩ (output qubit)
operation ApplyProductWithNegationFunction (vector : Bool[], controls : Qubit[], target : Qubit)
: Unit is Adj {
for (bit, control) in Zipped(vector, controls) {
ControlledOnInt(bit ? 1 | 0, X)([control], target);
}
}
/// # Summary
/// Reconstructs the parameters of the oracle in a single query
///
/// # Input
/// ## N
/// The number of qubits in the input register N for the function f
/// ## oracle
/// A quantum operation which implements the oracle |x⟩|y⟩ -> |x⟩|y ⊕ f(x)⟩, where
/// x is an N-qubit input register, y is a 1-qubit answer register, and f is a Boolean function.
/// The function f implemented by the oracle can be represented as
/// f(x₀, …, xₙ₋₁) = Σᵢ (rᵢ xᵢ + (1 - rᵢ)(1 - xᵢ)) modulo 2 for some bit vector r = (r₀, …, rₙ₋₁).
///
/// # Output
/// A bit vector r which generates the same oracle as the given one
/// Note that this doesn't have to be the same bit vector as the one used to initialize the oracle!
operation ReconstructOracleParameters(N : Int, oracle : ((Qubit[], Qubit) => Unit)) : Bool[] {
use x = Qubit[N];
use y = Qubit();
// apply oracle to qubits in all 0 state
oracle(x, y);
// f(x) = Σᵢ (rᵢ xᵢ + (1 - rᵢ)(1 - xᵢ)) = 2 Σᵢ rᵢ xᵢ + Σᵢ rᵢ + Σᵢ xᵢ + N = Σᵢ rᵢ + N
// remove the N from the expression
if (N % 2 == 1) {
X(y);
}
// now y = Σᵢ rᵢ
// measure the output register
let m = MResetZ(y);
// before releasing the qubits make sure they are all in |0⟩ state
ResetAll(x);
return m == One
? ConstantArray(N, false) w/ 0 <- true
| ConstantArray(N, false);
}
/// # Summary
/// Instantiates the oracle and runs the parameter restoration algorithm.
operation RunAlgorithm(bits : Bool[]) : Bool[] {
Message("Hello, quantum world!");
// construct an oracle using the input array
let oracle = ApplyProductWithNegationFunction(bits, _, _);
// run the algorithm on this oracle and return the result
return ReconstructOracleParameters(Length(bits), oracle);
}
}
Per chiamare questa operazione da .NET in un simulatore quantistico, è possibile usare il metodo Run
della classe RunAlgorithm
di .NET generata dal compilatore Q#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static System.Diagnostics.Debug;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace Microsoft.Quantum.Samples
{
static class Program
{
static async Task Main(string[] args)
{
var bits = new[] { false, true, false };
using var sim = new QuantumSimulator();
Console.WriteLine($"Input: {bits.ToDelimitedString()}");
var restored = await RunAlgorithm.Run(sim, new QArray<bool>(bits));
Console.WriteLine($"Output: {restored.ToDelimitedString()}");
Assert(bits.Parity() == restored.Parity());
}
static bool Parity(this IEnumerable<bool> bitVector) =>
bitVector.Aggregate(
(acc, next) => acc ^ next
);
static string ToDelimitedString(this IEnumerable<bool> values) =>
String.Join(", ", values.Select(x => x.ToString()));
}
}
Passaggi successivi
Ora che è stato configurato Quantum Development Kit per applicazioni Q# e per l'interoperabilità con .NET, è possibile scrivere ed eseguire il primo programma quantistico.