QPanda 2 Documentation

repository·master·Indexed 22 days ago

https://github.com/originq/qpanda-2

An open-source quantum computing framework by Origin Quantum for building, running, and optimizing quantum algorithms. It provides a C++ API and a Python interface (pyQPanda) supporting versions 3.6-3.9. The framework includes modules for core quantum operations, algorithm packs, and Hamiltonian utilities, and serves as the foundation for products like QRunes and Qurator.

Tokens
16.8K
Snippets
55
Records
71
Agent score
79%

What's inside QPanda 2

  1. Overview of pyQPanda API modules

    master

    The pyqpanda package provides several modules for quantum computing tasks:

    • pyqpanda: The core QPanda Basic API.
    • pyqpanda.utils: Extended QPanda API utilities.
    • pyqpanda.Algorithm: A collection of algorithm packs.
    • pyqpanda.Algorithm.demo: Demonstrations of various algorithms.
    • pyqpanda.Algorithm.test: Test suites for the pyqpanda.Algorithm module.
    • pyqpanda.Algorithm.fragments: Individual algorithm fragments.
    • pyqpanda.Hamiltonian: Utilities for handling Hamiltonians.
  2. Understand Eigen Tensor Datatypes

    master

    When working with Eigen Tensors, several specific types are used in documentation and API signatures to represent dimensions, indices, and element types:

    • <Tensor-Type>::Dimensions: An array-like object of int representing the dimensions of a tensor. It has a .size attribute (the rank) and can be indexed like an array.
    • <Tensor-Type>::Index: An integer type used for indexing tensors along their dimensions. It is compatible with standard int usage.
    • <Tensor-Type>::Scalar: The underlying data type of the individual tensor elements (e.g., float for Tensor<float, 2>).
    • <Operation>: A pseudo-type indicating that a method returns a deferred tensor operation rather than a concrete tensor. These must be evaluated (e.g., by assigning them to a tensor) before their values can be accessed.
  3. Understand TensorLayout (ColMajor vs RowMajor)

    master

    Eigen Tensors support two memory layouts: ColMajor (default) and RowMajor.

    Important Usage Notes:

    • Support: Currently, only ColMajor is fully supported. Using RowMajor is not recommended.
    • Type Specification: Layout is part of the type. If not specified, ColMajor is assumed.
    • Compatibility: All operands in an expression must use the same layout. Mixing layouts will cause a compilation error.
    • Layout Swapping: You can change a tensor's layout using the swap_layout() method. Note that swap_layout() also reverses the order of the dimensions.

    To swap the layout while preserving the original dimension order, combine swap_layout() with a shuffle() operation.

    // Explicitly declaring ColMajor (default)
    Eigen::Tensor<float, 3, Eigen::ColMajor> col_major;
    
    // Explicitly declaring RowMajor
    Eigen::TensorMap<Eigen::Tensor<float, 3, Eigen::RowMajor>> row_major(data, ...);
    
    // Simple layout swap (reverses dimension order)
    // If col_major is (2, 4), swap_layout() results in (4, 2)
    auto swapped = col_major.swap_layout();
    
    // Swap layout and preserve dimension order using shuffle
    Eigen::array<int, 2> shuffle(1, 0);
    auto preserved = col_major.swap_layout().shuffle(shuffle);
  4. Understand Eigen Tensor Operations and Lazy Evaluation

    master

    All Tensor methods in Eigen return non-evaluated Operations rather than immediate results. These operations can be chained together (e.g., a.constant(2.0f).pow(2.0f)).

    Key Concept: Lazy Evaluation The chain of operations is evaluated lazily. This means the actual computation typically only occurs when the operation is assigned to a tensor. This allows the library to optimize the entire expression tree before performing the math.

  5. Perform Reduction Operations on Eigen Tensors

    master

    A reduction operation returns a tensor with fewer dimensions than the original by applying a reduction operator to slices of values. You specify the dimensions to reduce using an array of integers (the "reduction dimensions").

    Key Rules for Reduction Dimensions:

    • The parameter can have at most as many elements as the rank of the input tensor.
    • Each element must be less than the tensor rank.
    • Each dimension should occur at most once in the reduction dimensions.
    • Listing dimensions in increasing order may improve execution speed.

    Special Case: Reduction along all dimensions

    If you pass no parameter to a reduction operation, the original tensor is reduced along all its dimensions, resulting in a zero-dimension tensor (a scalar).

    Predefined Reduction Operators:

    • sum(): Returns the sum of reduced values.
    • mean(): Returns the mean of reduced values.
    • maximum(): Returns the largest of the reduced values.
    • minimum(): Returns the smallest of the reduced values.
    • prod(): Returns the product of the reduced values.
    • all(): Casts tensor to bool and checks if all elements are true (note: does not short-circuit).
    • any(): Casts tensor to bool and checks if any element is true (note: does not short-circuit).

    Custom Reductions

    You can use reduce(const Dimensions& new_dims, const Reducer& reducer) to apply a user-defined reduction operator by implementing a reductor template.

    // Example: Reduction along one dimension
    Eigen::Tensor<int, 2> a(2, 3);
    a.setValues({{1, 2, 3}, {6, 5, 4}});
    
    // Reduce along the second dimension (index 1)
    Eigen::array<int, 1> dims({1});
    Eigen::Tensor<int, 1> b = a.maximum(dims);
    // b will be: [3, 6]
    
    // Example: Reduction along all dimensions (returns scalar)
    Eigen::Tensor<float, 3> a(2, 3, 4);
    Eigen::Tensor<float, 0> b = a.sum();
  6. Understand Tensor operations and lazy evaluation

    master

    Eigen Tensor operations (like +, *, exp(), etc.) use lazy evaluation. When you write an expression like t1 + t2, Eigen does not immediately perform the addition. Instead, it constructs a lightweight "tensor operator" object (e.g., TensorCwiseBinaryOp) that represents the computation tree.

    Actual computation only occurs when the expression is assigned to a concrete tensor type like Tensor, TensorFixedSize, or TensorMap. This mechanism allows the library to optimize complex expression trees before execution.

    Tensor<float, 3> t1(2, 3, 4);
    Tensor<float, 3> t2(2, 3, 4);
    // t3 is the actual result of the computation
    Tensor<float, 3> t3 = t1 + t2;
  7. Customize GoogleTest via `gtest.h` macros

    master

    You can inject custom implementations for core GoogleTest behaviors by defining specific macros before including the GoogleTest headers. This is useful for overriding how stack traces are retrieved or how temporary directories are managed.

    Available macros:

    • GTEST_OS_STACK_TRACE_GETTER_: Provide the name of an implementation of OsStackTraceGetterInterface.
    • GTEST_CUSTOM_TEMPDIR_FUNCTION_: Provide an override for testing::TempDir(). The override must match the signature and semantics of testing::TempDir.
  8. Avoid using C++ 'auto' for Tensor results

    master

    Because operations return expression objects rather than actual tensors, using auto will capture the non-evaluated expression tree instead of the data. You cannot access elements directly from an auto variable containing an expression.

    To get the actual values, you must assign the expression to a concrete Tensor type:

    // ERROR: t4 is an expression tree, not a tensor. Cannot access elements.
    auto t4 = t1 + t2;
    // cout << t4(0, 0, 0); // Compilation error!
    
    // CORRECT: Assign to a Tensor to trigger evaluation.
    Tensor<float, 3> t3 = t1 + t2;
    // cout << t3(0, 0, 0); // OK
    Tensor<float, 3> t3 = t1 + t2;
    cout << t3(0, 0, 0);  // OK prints the value of t1(0, 0, 0) + t2(0, 0, 0)
    
    auto t4 = t1 + t2;
    cout << t4(0, 0, 0);  // Compilation error!
  9. Install QPanda for other Python versions or C++

    master
    If you need to use a version of Python other than 3.8-3.11, or if you want to program directly using the C++ API, you should compile from source. Refer to the official usage documentation for build instructions.
  10. Compile QPanda 2 C++ applications with MPI parallelism

    master

    For parallel computing using MPI, use mpic++ instead of g++. Similar to the standard compilation, you must include the QPanda 2 paths and decide whether to link -lcurl based on host availability.

    # Using MPI with libcurl present
    mpic++ test.cpp -std=c++14 -fopenmp -I{QPanda安装路径}/include/qpanda2/ -I{QPanda安装路径}/include/qpanda2/ThirdParty/ -L{QPanda安装路径}/lib/ -lQPanda2 -lTinyXML -lcurl -o test
    
    # Using MPI without libcurl
    mpic++ test.cpp -std=c++14 -fopenmp -I{QPanda安装路径}/include/qpanda2/ -I{QPanda安装路径}/include/qpanda2/ThirdParty/ -L{QPanda安装路径}/lib/ -lQPanda2 -lTinyXML -o test
  11. Select computation devices (CPU/GPU) with device()

    master

    Eigen Tensors support different execution backends via the .device() method. By default, a single-threaded CPU implementation is used. To use multi-threading or GPU acceleration, you must explicitly specify a device.

    Requirements:

    • The result Tensor must be declared on its own line before the assignment.
    • The .device() call must be the last call on the left side of the assignment operator (=).

    Supported Devices:

    • DefaultDevice: Single-threaded CPU (default).
    • ThreadPoolDevice: Multi-threaded CPU.
    • GpuDevice: GPU/CUDA execution (requires explicit GPU memory allocation).
    // Using a ThreadPoolDevice for multi-threaded CPU execution
    Eigen::ThreadPoolDevice my_device(4 /* number of threads */);
    Eigen::Tensor<float, 2> c(30, 50);
    
    // The device call must be the last call on the left of the operator=
    c.device(my_device) = a.contract(b, dot_product_dims);