Tutorial: Implementación de un generador cuántico de números aleatorios en Q#

En este tutorial, escribirá su primer programa cuántico con el kit de desarrollo de Quantum (QDK). Un ejemplo sencillo de un algoritmo cuántico escrito en Q# es un generador cuántico de números aleatorios. Este algoritmo aprovecha la naturaleza de la mecánica cuántica para generar un número aleatorio.

Prerrequisitos

En este tutorial, aprenderá a:

  • Cree un proyecto de Q#.
  • Prepare su entorno de desarrollo para escribir programas cuánticos en Q#.
  • Comprenda cómo se estructuran los programas de Q#.
  • Trabajar con bits cuánticos y con la superposición para crear un generador de números aleatorios cuántico

Creación de un proyecto Q#

Lo primero que hay que hacer es crear un nuevo proyecto de Q#. En este tutorial se usa el entorno basado en aplicaciones de Q# en VS Code, pero puede usar el IDE que prefiera.

Para crear un proyecto en VS Code:

  1. Haga clic en Ver -> Paleta de comandos y seleccione Q#: Crear nuevo proyecto.
  2. Haga clic en Aplicación de consola independiente.
  3. Vaya a la ubicación para guardar el proyecto y haga clic en Crear proyecto.
  4. Cuando el proyecto se haya creado correctamente, haga clic en Abrir nuevo proyecto... abajo a la derecha.

En este caso, el proyecto se denomina Qrng. Esto genera dos archivos: Qrng.csproj, el archivo de proyecto y Program.qs, una plantilla de una aplicación Q# que usaremos para escribir nuestra aplicación. El contenido de Program.qs debe ser:

   namespace Qrng {

      open Microsoft.Quantum.Canon;
      open Microsoft.Quantum.Intrinsic;
      
      @EntryPoint()
      operation HelloQ() : Unit {
          Message("Hello quantum world!");
      }
   }

Escritura de una operación de Q#

Reemplace el contenido del archivo Program.qs por el código siguiente:

namespace Qrng {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    
    @EntryPoint()
    operation GenerateRandomBit() : Result {
        use q = Qubit();   // Allocate a qubit.
        H(q);              // Put the qubit to superposition. It now has a 50% chance of being 0 or 1.
        return MResetZ(q); // Measure the qubit value.
    }
}

Echemos un vistazo a este código. Defina la operación GenerateRandomBit, que no toma ninguna entrada y genera un valor de tipo Result. El tipo Result representa el resultado de una medición y puede tener dos valores posibles: Zero y One. EntryPoint indica al compilador de Q# que empiece a ejecutar el programa aquí. En Q#, los cúbits se asignan mediante la palabra clave use. La operación H coloca el bit cuántico en superposición. La operación M mide el bit cuántico y devuelve el valor medido (o cero o uno).

Tal y como se mencionó en el artículo Descripción de la computación cuántica, un cúbit es una unidad de información cuántica que puede estar en superposición. Cuando se mide, un cúbit solo puede ser 0 o 1. Sin embargo, antes de la medida, el estado del cúbit representa la probabilidad de leer un 0 o un 1 al tomar una medida. Este estado probabilístico se conoce como superposición. Se puede usar esta probabilidad para generar números aleatorios.

Esta operación de Q# presenta el tipo de datos Qubit, nativo de Q#. Solo se puede asignar un Qubit con una instrucción use. Cuando se asigna un cúbit, siempre está en el estado Zero.

Al colocar Qubit en superposición con la operación H y medirlo con la operación intrínseca M, el resultado será un valor diferente cada vez que se invoque el código.

Cuando se desasigna un Qubit, se debe volver a establecer explícitamente en el estado Zero; de lo contrario, el simulador notificará un error en tiempo de ejecución. Una manera fácil de hacerlo es invocar a Reset.

Visualización del código con la esfera de Bloch

En la esfera Bloch, el polo norte representa el valor clásico 0 y el polo sur representa el valor clásico 1. Cualquier superposición se puede representar mediante un punto en la esfera (representado con una flecha). Cuanto más cerca esté el extremo de la flecha a un polo, mayor será la probabilidad de que el cúbit caiga en el valor clásico asignado a ese polo cuando se mida. Por ejemplo, el estado del cúbit representado por la flecha roja siguiente tiene una mayor probabilidad de dar el valor 0 si lo medimos.

A qubit state with a high probability of measuring zero

Podemos usar esta representación para visualizar lo que está haciendo el código:

  • En primer lugar, empezamos con un cúbit inicializado en el estado 0 y aplicamos H para crear una superposición en la que las probabilidades de 0 y 1 sean las mismas.
Preparing a qubit in superposition
  • A continuación, se mide el cúbit y se guarda el resultado:
Measuring a qubit and saving the output

Como el resultado de la medida es completamente aleatorio, hemos obtenido un bit aleatorio. Podemos llamar a esta operación varias veces para crear enteros. Por ejemplo, si llamamos a la operación tres veces para obtener tres bits aleatorios, podemos crear números de 3 bits aleatorios (es decir, un número aleatorio entre 0 y 7).

Creación de un generador completo de números aleatorios

Ahora que tiene una operación de Q# que genera bits aleatorios, podemos usarla para crear un generador cuántico de números cuánticos completo. Puede hacer con una aplicación de Q# o un programa host.

Definición de la lógica del generador de números aleatorios

Primero, vamos a describir cuál debe ser la lógica de un generador de números aleatorios, siempre y cuando dispongamos de uno:

  1. Definir max como el número máximo que quiere generar.
  2. Definir el número de bits aleatorios que necesita generar. Esto se hace calculando cuántos bits, nBits, necesitamos para expresar los enteros hasta el máximo.
  3. Genere una cadena de bits aleatoria con una longitud de nBits.
  4. Si la cadena de bits representa un número mayor que max, hay que volver al paso tres.
  5. Si no, el proceso habrá finalizado. Devolver el número generado como un entero.

Definición de la operación

Defina la operación SampleRandomNumberInRange, que llama repetidamente a la operación GenerateRandomBit para crear una cadena de bits.

Modifique Program.qs de esta forma:

namespace Qrng {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Convert;

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit(); 
        // Put the qubit to superposition.
        H(q);
        // It now has a 50% chance of being measured 0 or 1.
        // Measure the qubit value.
        return M(q);
    }

    operation SampleRandomNumberInRange(max : Int) : Int {
        mutable output = 0; 
        repeat {
            mutable bits = new Result[0]; 
            for idxBit in 1..BitSizeI(max) {
                set bits += [GenerateRandomBit()]; 
            }
            set output = ResultArrayAsInt(bits);
        } until (output <= max);
        return output;
    }
}

Paremos un momento a revisar el nuevo código.

Para calcular el número de bits necesarios para expresar enteros hasta el máximo, la biblioteca Microsoft.Quantum.Math proporciona la función BitSizeI para realizar esta tarea.

La operación SampleRandomNumberInRange usa un bucle repeat para generar números aleatorios hasta que genera uno igual o menor que el máximo.

El bucle for dentro de repeat funciona exactamente igual que un bucle for en otros lenguajes de programación.

En este ejemplo, output y bits son variables mutables. Una variable mutable es aquella que puede cambiar durante el cálculo. Se usa directiva set para cambiar el valor de una variable mutable.

La función ResultArrayAsInt procede de Microsoft.Quantum.Convert library. Esta función convierte la cadena de bits en un entero positivo.

El programa Qrng ahora puede generar números aleatorios. Modifique Program.qs de esta forma para definir el punto de entrada.

Para crear la aplicación de Q# completa, agregue el siguiente punto de entrada al programa de Q#:

namespace Qrng {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Convert;

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit();
        // Put the qubit to superposition.
        H(q);
        // It now has a 50% chance of being measured 0 or 1.
        // Measure the qubit value.
        return M(q);
    }

    operation SampleRandomNumberInRange(max : Int) : Int {
        mutable output = 0; 
        repeat {
            mutable bits = new Result[0]; 
            for idxBit in 1..BitSizeI(max) {
                set bits += [GenerateRandomBit()]; 
            }
            set output = ResultArrayAsInt(bits);
        } until (output <= max);
        return output;
    }

    @EntryPoint()
    operation SampleRandomNumber() : Int {
        let max = 50;
        Message($"Sampling a random number between 0 and {max}: ");
        return SampleRandomNumberInRange(max);
    }
}

El programa ejecutará la operación o función marcada con el atributo @EntryPoint() en un simulador o una calculadora de recursos, en función de la configuración del proyecto y de las opciones de línea de comandos.

En Visual Studio, solo tiene que presionar Ctrl+F5 para ejecutar el script.

En VS Code, escriba lo siguiente en el terminal para compilar el archivo Program.qs la primera vez:

dotnet build

En las ejecuciones posteriores, no es necesario volver a compilarlo. Para ejecutarlo, escriba el siguiente comando y presione Entrar:

dotnet run --no-build

Nota

Este fragmento de código no se ejecuta actualmente en ningún destino de hardware de Azure Quantum disponible, ya que el parámetro ResultArrayAsInt al que se puede llamar requiere una QPU con el perfil de cálculo completo.

Pasos siguientes

En el tutorial Exploración del entrelazamiento con Q#, se muestra cómo escribir un programa de Q# que manipula y mide cúbits, y muestra los efectos de la superposición y el entrelazamiento.

En Configuración de Azure Quantum se recomiendan más formas de aprender Q# y programación cuántica.