Program Listing for File LatticeFromParity.hpp

Return to documentation for file (UnionFindPy/cpp/include/LatticeFromParity.hpp)

#pragma once

#include "utility.hpp"

#include "tsl/robin_map.h"

#include <array>
#include <cstdlib>
#include <stdexcept>
#include <string>
#include <vector>

#include <iostream>

namespace UnionFindCPP
{
class LatticeFromParity
{
private:
    uint32_t num_vertices_;
    uint32_t num_edges_;

    /* connectivity of vertices (parities). Length num_parities */
    std::vector<std::vector<uint32_t>> vertex_connections_;
    tsl::robin_map<Edge, uint32_t> edge_idx_;

    static auto construct_qubit_associated_parities(uint32_t num_parities,
                                                    uint32_t num_qubits, int* col_indices,
                                                    const int* indptr)
        -> std::vector<std::vector<uint32_t>>
    {
        std::vector<std::vector<uint32_t>> qubit_associated_parities(num_qubits);
        for(uint32_t p_idx = 0; p_idx < num_parities; ++p_idx)
        {
            // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
            for(uint32_t idx = indptr[p_idx]; idx < indptr[p_idx + 1]; ++idx)
            {
                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
                qubit_associated_parities[col_indices[idx]].push_back(p_idx);
            }
        }
        return qubit_associated_parities;
    }

    static auto construct_edge_idx(
        uint32_t num_qubits,
        const std::vector<std::vector<uint32_t>>& qubit_associated_parities)
        -> tsl::robin_map<Edge, uint32_t>
    {
        tsl::robin_map<Edge, uint32_t> edge_idx;
        for(uint32_t q_idx = 0; q_idx < num_qubits; ++q_idx)
        {
            const auto& q_parities = qubit_associated_parities[q_idx];
            auto edge = Edge{q_parities[0], q_parities[1]};
            auto iter = edge_idx.find(edge);

            if(iter == edge_idx.end()) // first appear
            {
                edge_idx.emplace(edge, q_idx);
            }
        }
        return edge_idx;
    }

    void construct_vertex_connections_from_edges()
    {
        vertex_connections_.resize(num_vertices_);
        for(const auto& [edge, qidx] : edge_idx_)
        {
            const auto [u, v] = edge;
            vertex_connections_[u].emplace_back(v);
            vertex_connections_[v].emplace_back(u);
        }
    }

public:
    LatticeFromParity(uint32_t num_parities, uint32_t num_qubits, int* col_indices,
                      int* indptr)
        : num_vertices_{num_parities}, num_edges_{num_qubits}
    {
        auto qubit_associated_parities = construct_qubit_associated_parities(
            num_parities, num_qubits, col_indices, indptr);

        edge_idx_ = construct_edge_idx(num_qubits, qubit_associated_parities);
        construct_vertex_connections_from_edges();
    }

    LatticeFromParity(uint32_t layer_vertex_size, uint32_t layer_num_qubits,
                      int* col_indices, int* indptr, uint32_t repetitions)
        : num_vertices_{layer_vertex_size * repetitions},
          num_edges_{layer_num_qubits * repetitions
                     + layer_vertex_size * (repetitions - 1)}
    {
        if(repetitions < 2)
        {
            throw std::invalid_argument("Repetition must be greater than or equal to 2.");
        }

        auto qubit_associated_parities = construct_qubit_associated_parities(
            layer_vertex_size, layer_num_qubits, col_indices, indptr);
        auto layer_edge_idx
            = construct_edge_idx(layer_num_qubits, qubit_associated_parities);

        // Construct edge_idx_
        edge_idx_.reserve(num_edges_);
        // Add spacelike edges
        for(uint32_t depth = 0; depth < repetitions; ++depth)
        {
            for(const auto& [layer_edge, q_idx] : layer_edge_idx)
            {
                auto edge = Edge{layer_edge.u + depth * layer_vertex_size,
                                 layer_edge.v + depth * layer_vertex_size};

                edge_idx_.emplace(edge,
                                  q_idx + depth * (layer_vertex_size + layer_num_qubits));
            }
        }

        // Add timelike edges
        for(uint32_t depth = 0; depth < repetitions - 1; ++depth)
        {
            for(int layer_vertex_idx = 0; layer_vertex_idx < layer_vertex_size;
                ++layer_vertex_idx)
            {
                auto edge = Edge{depth * layer_vertex_size + layer_vertex_idx,
                                 (depth + 1) * layer_vertex_size + layer_vertex_idx};
                edge_idx_.emplace(edge,
                                  layer_vertex_idx + layer_num_qubits
                                      + (layer_num_qubits + layer_vertex_size) * depth);
            }
        }

        // Construct vertex_connections_
        construct_vertex_connections_from_edges();
    }

    [[nodiscard]] auto vertex_connections(uint32_t v) const
        -> const std::vector<uint32_t>&
    {
        return vertex_connections_[v];
    }

    [[nodiscard]] auto vertex_connection_count(int vertex) const -> uint32_t
    {
        return static_cast<int>(vertex_connections_[vertex].size());
    }

    [[nodiscard]] inline auto edge_idx(const Edge& edge) const -> uint32_t
    {
        return edge_idx_.at(edge);
    }

    [[nodiscard]] inline auto num_edges() const -> uint32_t { return num_edges_; }

    [[nodiscard]] inline auto num_vertices() const -> uint32_t { return num_vertices_; }

    [[nodiscard]] inline auto
    edge_idx_all() const& -> const tsl::robin_map<Edge, uint32_t>&
    {
        return edge_idx_;
    }
    [[nodiscard]] inline auto edge_idx_all() && -> tsl::robin_map<Edge, uint32_t>
    {
        return edge_idx_;
    }
};
} // namespace UnionFindCPP