likes
comments
collection
share

《量子计算实践—Java样例》第二章:“Hello World”,量子计算风格

作者站长头像
站长
· 阅读数 23

本章内容包括:

  • 介绍Strange,一个Java中的量子计算库
  • 尝试在Strange中使用高级和低级API
  • 对量子电路进行基本可视化

本章介绍了Strange,一个开源的量子计算项目,其中包括一个量子模拟器和一个暴露给Java API的库,您可以在常规Java应用程序中使用它。在整本书中,我们讨论了量子计算(QC)的概念及其对Java开发人员的相关性,并展示了Java开发人员如何从这些概念中受益。

Strange包含了所需的量子概念的纯Java实现。在讨论这些概念时,我们会指向Strange中相关概念的代码实现,这是低级API的一部分。

大多数Java开发人员不需要处理低级量子概念。然而,有些人可能会受益于利用这些概念的算法。对于这些人,Strange提供了一组高级算法,可以在常规的Java应用程序中使用。这些算法就是我们所说的高级Java API。

介绍Strange

图2.1展示了Strange的组件的高级概述。Java Quantum API提供了一系列典型的量子算法的实现。这些是您可以在常规的Java应用程序中使用的高级算法。使用它们不需要了解量子计算的知识。

《量子计算实践—Java样例》第二章:“Hello World”,量子计算风格

量子核心层包含低级API,它提供更深入的访问真实的量子方面。高级API不包含与QC特定的概念,但它的实现使用了低级量子核心层。高级API将量子概念屏蔽,而低级API向您公开这些概念。

高级API为您提供了一个即用型的接口来使用量子算法。通过使用它,您可以从QC带来的性能提升中受益。然而,如果您想要创建自己的算法或修改现有算法,低级API是起点。

使用Strange运行第一个演示示例

本书提供了一个包含许多使用Strange的示例的存储库。您可以在GitHub上找到这个存储库,网址为github.com/johanvos/qu…。运行示例的要求和说明在附录A中有解释。第一个演示示例位于ch02目录中的hellostrange文件夹中。

请注意,所有示例都需要Java 11或更高版本。在附录A中,您可以找到安装所需Java软件的说明。

构建和运行示例可以使用Gradle构建工具和Maven构建工具。示例包含一个build.gradle文件,允许它们由Gradle处理,以及一个pom.xml文件,允许它们由Maven处理。

我们建议您使用您喜欢的IDE(IntelliJ,Eclipse或NetBeans)来运行示例。每个IDE的运行Java应用程序的说明都不同。在本书中,我们使用命令行中的Gradle和Maven构建系统;使用提供的Gradle和Maven配置文件会隐式确保下载所有所需的代码依赖项。代码将会被编译和执行,如图2.2所示。

《量子计算实践—Java样例》第二章:“Hello World”,量子计算风格

注意:在使用命令行界面运行示例时,我们在Maven和Gradle之间采取了稍微不同的方法。使用Maven时,您需要切换到特定示例的目录(其中包含一个pom.xml文件)。而在使用Gradle时,您保持在根级别(其中包含一个build.gradle文件),并通过提供章节和项目名称来运行示例。我们将通过HelloStrange示例来解释这一点。

如果您想使用Maven构建系统来运行基本的HelloStrange应用程序,则需要移动到ch02/hellostrange目录中。然后执行以下命令:

mvn clean javafx:run

执行该命令后,将会得到类似以下的输出:

mvn clean javafx:run
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------------------------------------------------
[INFO] Building hellostrange 1.0-SNAPSHOT
[INFO] ---------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ helloquantum ---
[INFO] Deleting /home/johan/quantumcomputing/manning/public/quantumjava/ch02
/hellostrange/target
[INFO]
[INFO] >>> javafx-maven-plugin:0.0.6:run (default-cli) > process-classes @ h
elloquantum >>>
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloq
uantum ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/johan/quantumcomputing/mann
ing/public/quantumjava/ch02/hellostrange/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloquantu
m ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/johan/quantumcomputing/manning/publi
c/quantumjava/ch02/hellostrange/target/classes
[INFO]
[INFO] <<< javafx-maven-plugin:0.0.6:run (default-cli) < process-classes @ h
elloquantum <<<
[INFO]
[INFO] --- javafx-maven-plugin:0.0.6:run (default-cli) @ helloquantum ---
[INFO] Toolchain in javafx-maven-plugin null
Using high-level Strange API to generate random bits
\----------------------------------------------------
Generate one random bit, which can be 0 or 1. Result = 1
Generated 10000 random bits, 4967 of them were 0, and 5033 were 1.
[INFO] ---------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ---------------------------------------------------------------------
[INFO] Total time: 1.790 s
[INFO] Finished at: 2021-08-18T14:52:58+02:00
[INFO] Final Memory: 13M/54M
[INFO] ---------------------------------------------------------------------

NOTE:有经验的Maven用户可能会想知道为什么我们不直接使用mvn exec:java,这将使用Maven的Java插件。我们推荐使用mvn javafx:run,因为这涉及到Maven的JavaFX插件。该插件允许我们运行标准的Java应用程序以及JavaFX应用程序。我们在一些示例中使用JavaFX应用程序,其中生成了用户界面。与在Java应用程序运行没有用户界面时切换Java插件和JavaFX插件相比,总是调用JavaFX插件更加方便。

当使用Gradle时,您需要在根目录下运行Gradle并传递项目的名称。您可以检查settings.gradle文件的内容,其中包含了仓库中所有项目的名称。

在Linux和macOS中运行示例可以使用以下命令:

./gradlew ch02:hellostrange:run

如果您使用的是Windows系统,则需要使用以下方式运行:

gradlew.bat ch02:hellostrange:run

两个命令的运行结果如下:

> Task :run
Using high-level Strange API to generate random bits
----------------------------------------------------
Generate one random bit, which can be 0 or 1. Result = 1
Generated 10000 random bits, 4961 of them were 0, and 5039 were 1.
 
BUILD SUCCESSFUL in 3s

注意:Gradle可能会输出更多内容,特别是如果这是您第一次使用此Gradle版本,或者需要的依赖项尚未安装在您的系统上。

恭喜!您刚刚执行了一个涉及到量子计算的程序。

审查HelloStrange代码

为了理解HelloStrange演示应用程序的输出,我们建议您查看应用程序的源代码。在我们研究Java代码之前,我们需要查看示例根目录中的build.gradle和pom.xml文件。build.gradle文件包含指令,允许Gradle编译Java类,下载和安装依赖项,并运行应用程序。pom.xml文件具有相同的目标,允许我们使用Maven处理该应用程序。

编译过程

通常情况下,除非您打算自己创建应用程序或项目,否则不必担心 build.gradle 文件或 pom.xml 文件的结构。在这种情况下,您可以在网上找到很多关于使用 Gradle 和 Maven 的优秀资源。

BUILDING WITH MAVEN

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.
➥ org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.
➥ org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.redfx.javaqc</groupId>
  <artifactId>helloquantum</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>grover</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>org.redfx</groupId>
      <artifactId>strange</artifactId>
      <version>0.1.1</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-maven-plugin</artifactId>
        <version>0.0.4</version>
        <configuration>
          <mainClass>
              org.redfx.javaqc.ch02.hellostrange.Main    ❹
          </mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

❶ pom 文件需要一些有关项目的通用信息。这里定义的属性是标准的 Maven 属性,并且与我们的应用程序无关,但它们需要被定义。

❷ 该项目依赖于 org.redfx.strange。

❸ 项目的生命周期管理(编译和运行)由 javafx-maven 插件处理,如此处所述。

❹ 需要指定主类名,以便插件可以运行它。

熟悉 Maven 的用户可以轻松修改这个 .pom 文件,但一般情况下不需要这样做。

BUILDING WITH GRADLE

为了清晰起见,下面展示了 build.gradle 文件的内容:

plugins {                                                  ❶
    id 'application'
}
 
repositories {                                             ❷
    mavenCentral();
}
 
dependencies {                                             ❸
    compile 'org.redfx:strange:0.1.1'
}
 
mainClassName = 'org.redfx.javaqc.ch02.hellostrange.Main'

❶ 声明 Gradle 应使用哪些插件。Gradle 是一个构建系统,允许第三方提供插件来简化应用程序的构建和部署。这个演示应用程序是一个应用程序,因此使用了 application 插件。Strange 需要 Java 11 和在 Java 9 中引入的模块化概念。我们的演示应用程序不需要了解 Java 中的模块系统。然而,为了构建工具能够使用模块化,我们还声明了使用 javamodularity Gradle 插件。

❷ 声明依赖项的下载位置。由于我们的演示应用程序使用了一个 Java 库,Gradle 需要知道在哪里找到这个库,以便在编译和运行演示应用程序时使用。Strange 库被上传到 mavenCentral 仓库,因此我们在 repositories 部分声明了这一点。

❸ 声明依赖项。HelloStrange 演示应用程序使用了 Strange 库。在这里,我们声明我们需要 Strange 库的 0.1.1 版本,这是由包名(org.redfx)和 artifact 名称(strange)组合而成的。compile 关键字告诉 Gradle 这个库在编译应用程序时是必需的,并且默认情况下也会在运行应用程序时使用这个库。

❹ 声明运行演示时应该执行的主类。我们需要告诉 Gradle 在哪里找到我们应用程序的主入口点。在这种情况下,该项目有一个带有主方法的单个 Java 源文件,因此这是入口点。

build.gradle 文件对于开发人员和代码维护者来说非常重要,特别是那些涉及项目开发、部署、测试和发布的人。

代码

在项目中的Java源文件对所有开发人员都很重要。Maven和Gradle默认要求将Java源文件放置在一个名为src/main/java的文件夹中,后面跟着包名和Java源文件的名称。对于HelloStrange应用程序,单个源文件位于src/main/java/org/redfx/javaqc/ch02/hellostrange/Main.java。注意每个示例都有自己的src目录,以便可以轻松地单独查看每个示例。

在展示代码之前,我们简要解释一下我们想要实现的目标。在这个第一个示例中,我们调用了高级Strange API上的一个方法。该方法称为randomBit(),它生成一个经典位,可以是0或1。我们稍后会讨论randomBit()方法的调用。除了这个调用,示例中使用的所有Java代码都只使用了JDK中的标准API。

示例的流程如图2.3所示。您可以看到我们创建的Java类依赖于高级Strange API。我们不必担心它在Strange的更低层次中是如何实现的。

《量子计算实践—Java样例》第二章:“Hello World”,量子计算风格

完整的应用程序源代码如下所示。接下来我们将对这个源代码进行分析。

package org.redfx.javaqc.ch02.hellostrange;
 
import org.redfx.strange.algorithm.Classic;
 
public class Main {
 
    public static void main (String[] args) {
        System.out.println("Using high-level Strange API to generate random
➥ bits");
        System.out.println("--------------------------------------------");
        int randomBit = Classic.randomBit();              ❶
        System.out.println("Generate one random bit, which can be 0 or 1."+
                           " Result = "+randomBit);
        int cntZero = 0;
        int cntOne = 0;
        for (int i = 0; i < 10000; i++) {                 ❷
            if (Classic.randomBit() > 0) {
                cntOne ++;
            } else {
                cntZero ++;
            }
        }
        System.out.println("Generated 10000 random bits, " + cntZero +
                           " of them were 0, and "+cntOne+" were 1.");
    }
}

❶ 调用 Strange 高级 API 生成一个随机位

❷ 生成 10,000 个随机位

这段 Java 代码遵循基本的 Java 规范,我们假设您对此已经很熟悉。对于这个示例,我们简要介绍 Java 应用程序的典型概念。

这个源文件中的 Java 代码属于包 org.redfx.javaqc.ch02.hellostrange,在文件的顶部声明了该包。我们依赖 Strange 库提供的功能,并且导入了提供我们所需功能的 Java 类:

import org.redfx.strange.algorithm.Classic

我们稍后会更深入地了解 Classic 类。现在,我们只是简单地假设它提供了我们需要的功能。

我们的示例 Java 类的名称是 Main,因为它必须与文件名匹配。在 Java 中,文件中的入口点需要声明为具有方法签名 public static void main(String[] args)。像 Maven 和 Gradle 这样的构建工具在被要求执行应用程序时调用此方法。当 main 方法被调用时,首先打印一些信息:

System.out.println("Using high-level Strange API to generate random bits");
System.out.println("----------------------------------------------------");

在列表2.3中的下一行代码中,我们调用了一个位于导入的 Strange 库中的 Classic 类的方法:Classic.randomBit(),它返回一个包含值0或值1的 Java 整数。在该语句之后,我们使用一个 for 循环来生成10,000个随机位,将它们打印到控制台:

int randomBit = Classic.randomBit();

注意:Classic 类名表明 Strange 提供了这个用于经典调用的类。这意味着调用这个类的代码不需要包含任何量子特定的对象或函数。调用代码可以是完全使用经典代码编写的项目或库。然而,Classic 类本身的实现包含了量子实现。因此,Classic.randomBit() 的实现不仅仅返回一个默认的 Java 随机位,还使用量子电路来生成它,我们稍后在本章中会展示。

接下来的一行代码打印了这个值。请注意,当你执行应用程序时,有50%的机会看到打印的是0,另外50%的机会看到打印的是1。正如我们之前所说,Classic.randomBit() 是一个使用量子原理的 Java 方法。我们稍后会讨论它的实现;现在,我们假设这个方法返回0和1的概率相等。

为了证明这一点,列表2.3 的下一部分调用了 Classic.randomBit() 10,000 次,并跟踪了返回 0 的次数和返回 1 的次数。引入了两个变量来跟踪这个情况:

int cntZero = 0;
int cntOne = 0;

显然,cntZero 保存了返回值为 0 的次数,而 cntOne 则保存了返回值为 1 的次数。

我们创建了一个循环,在循环的内部代码中调用 randomBit() 方法并递增相应的变量。以下是相应的代码片段:

for (int i = 0; i < 10000; i++) {
    if (Classic.randomBit() > 0) {
        cntOne ++;
    } else {
        cntZero ++;
    }
}

最后,结果被打印出来。由于随机值是真正的随机的,每次运行应用程序时最终结果可能会不同。cntOne 和 cntZero 值的总和将始终为 10,000,而预期 cntZero 和 cntOne 值都将接近 5000。

Java APIs vs. 实现

如果您熟悉Java开发,到目前为止我们所展示和使用的代码应该很熟悉。没有需要特定的量子物理学或量子计算的知识。我们使用了Classic.randomBit(),这是一个类似于Java应用程序中的所有Java方法的方法。然而,在底层,Classic.randomBit()要么使用量子模拟器,要么使用真实的量子计算机。然而,Java开发人员并不需要直接接触这个实现。Java的一个伟大之处在于,对于使用API编程的开发人员,实现通常是隐藏的。在这种情况下,Classic.randomBit()是由开发人员调用的API。

尽管您不需要了解底层的实现细节,但了解一些细节通常会有所帮助。这不仅适用于量子计算中的算法,也适用于许多领域。尽管文档(例如Javadoc)通常对一般情况很有帮助,但了解一些细节可能有助于了解性能。对于量子计算,建议Java开发人员至少具有量子API底层实现的基本知识,因为这提供了有用的信息,可以用来判断量子算法是否适用于特定的用例,并且性能影响是什么。

此外,如果缺乏这些基本知识,可能会担心一些算法的初始性能。的确,如果在量子模拟器上执行量子算法,其性能可能比使用经典算法要差。然而,如果量子算法编写良好,并且问题适用于量子加速,当使用真实的量子硬件时,其性能将显著提高。

获取和安装Strange代码

正如前面所解释的,通常你不需要理解算法的实现细节。然而,在本书中,我们通过展示量子算法的代码片段来解释QC的基本概念。通过查看一些算法的实现,你将更了解QC的概念,并对QC可以产生重大影响的领域有更深入的了解。

我们在本书中使用的Strange库是用Java编写的。这使你能够在自己的应用程序中使用量子API,并在需要时深入了解实现并进行修改或扩展。如果你使用特定的IDE(例如NetBeans、IntelliJ或Eclipse),你应该可以轻松打开库并阅读文件。

下载代码

和本书中使用的示例和演示一样,Strange库的代码可以从GitHub下载。以下命令将为你提供Strange库的本地副本:

git clone <https://github.com/redfx-quantum/strange.git>

请注意,如果你想在应用程序中使用Strange库,你不需要下载源代码。 Strange的二进制版本已经上传到Maven Central,并且像Gradle和Maven这样的构建工具将从这个上传的位置检索它们。

如果出于某种原因你想要修改Strange并在本地进行测试,你可以很容易地编译整个项目。与前一节中的示例应用程序类似,Strange使用Gradle构建系统来创建库。

以下Maven命令可用于构建库:

mvn install

该操作的结果是Strange库的本地副本,你可以在本地应用程序中使用它。在使用你自己的库之前,你需要考虑两件事情:

  • pom.xml文件包含一个版本参数。你可以将其更改为任何你想要的版本,但你必须确保在应用程序的依赖项部分中使用相同的版本。

  • 你的应用程序需要在其仓库列表中包含mavenLocal()。

库初探

你可以在你的集成开发环境中打开代码,或者浏览文件。例如,你可以打开我们在前一节讨论过的Classic.java文件。Classic类的源代码位于Classic.java文件中,它位于你克隆Git存储库的目录下的src/main/java/org/redfx/strange/algorithm文件夹中。在第7章中,我们将详细讨论这个文件,但以下代码片段展示了从前一节中的Classic.randomBit()调用到使用量子计算机或量子模拟器进行实现的链接:

public static int randomBit() {
    Program program = new Program(1);
    Step s0 = new Step();
    s0.addGate(new Hadamard(0));
    program.addStep(s0);
    QuantumExecutionEnvironment qee =
            new SimpleQuantumExecutionEnvironment();
    Result result = qee.runProgram(program);
    Qubit[] qubits = result.getQubits();
    int answer = qubits[0].measure();
    return answer;
}

这段代码片段显示了randomBit()方法返回的随机比特不仅仅是由经典的随机函数生成的,而是涉及到特定于量子计算的步骤。再次强调,Java开发者通常不需要深入了解实现细节,但通过查看代码,你可以学到很多关于量子计算的知识。

下一步

现在你已经下载了Strange库并且运行了第一个使用量子计算的Java应用程序,是时候更深入地了解量子计算的基本概念了。如果你想先查看更多代码,可以随意浏览Strange库中的文件。然而,我们建议你首先阅读有关基本概念的内容。每当我们介绍一个概念时,我们会指向Strange库中应用该概念的代码。出于设计考虑,我们避免使用Strange库中包含量子特定概念的高级API。在接下来的章节中,我们将通过使用Strange低级API来解释量子计算的核心概念。

总结

  • Strange是一个拥有高级和低级API的量子计算模拟器。
  • 你可以很容易地使用Strange的高级API创建一个HelloWorld应用程序,它将在底层使用量子计算概念。
  • 高级API的实现需要低级API的支持。通常情况下,你不需要过多关注这些低级API,但如果你想深入了解量子计算概念,它们非常有帮助。