/*
* This file is part of MQT QFR library which is released under the MIT license.
* See file README.md or go to https://www.cda.cit.tum.de/research/quantum/ for more information.
*/

#pragma once

#include "Ecc.hpp"
#include "QuantumComputation.hpp"

//Reference to this ecc in https://arxiv.org/pdf/1608.05053.pdf
namespace ecc {
    class Q9Surface: public Ecc {
    public:
        Q9Surface(std::shared_ptr<qc::QuantumComputation> qc, std::size_t measureFq):
            Ecc({ID::Q9Surface, N_REDUNDANT_QUBITS, N_CORRECTING_BITS, "Q9Surface", {{ANCILLA_WIDTH, "qeccX"}, {ANCILLA_WIDTH, "qeccZ"}}}, std::move(qc), measureFq) {}

    protected:
        void measureAndCorrect() override;

        void writeDecoding() override;

        void mapGate(const qc::Operation& gate) override;

    private:
        //{a,{b,c}} == qubit a is checked by b and c
        static constexpr std::size_t N_REDUNDANT_QUBITS = 9;
        static constexpr std::size_t N_CORRECTING_BITS  = 8;
        static constexpr std::size_t ANCILLA_WIDTH      = 4;

        std::array<std::set<std::size_t>, N_REDUNDANT_QUBITS>   qubitCorrectionX   = {{{1}, {3}, {3}, {1, 4}, {3, 4}, {3, 6}, {4}, {4}, {6}}};
        std::array<std::set<std::size_t>, N_REDUNDANT_QUBITS>   qubitCorrectionZ   = {{{2}, {0, 2}, {0}, {2}, {2, 5}, {5}, {7}, {5, 7}, {5}}};
        static constexpr std::array<Qubit, ANCILLA_WIDTH>       X_ANCILLA_QUBITS   = {1, 3, 4, 6};
        static constexpr std::array<Qubit, ANCILLA_WIDTH>       Z_ANCILLA_QUBITS   = {0, 2, 5, 7};
        std::set<Qubit>                                         uncorrectedXQubits = {2, 6};
        std::set<Qubit>                                         uncorrectedZQubits = {0, 8};
        static constexpr std::array<Qubit, 3>                   LOGICAL_X          = {2, 4, 6};
        static constexpr std::array<Qubit, 3>                   LOGICAL_Z          = {0, 4, 8};
        static constexpr std::array<std::pair<Qubit, Qubit>, 4> SWAP_INDICES       = {{{0, 6}, {3, 7}, {2, 8}, {1, 5}}};
    };
} // namespace ecc
