1 /*
2  * This file is part of Quantum++.
3  *
4  * Copyright (c) 2013 - 2021 softwareQ Inc. All rights reserved.
5  *
6  * MIT License
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 /**
28  * \file classes/codes.hpp
29  * \brief Quantum error correcting codes
30  */
31 
32 #ifndef CLASSES_CODES_HPP_
33 #define CLASSES_CODES_HPP_
34 
35 namespace qpp {
36 /**
37  * \class qpp::Codes
38  * \brief const Singleton class that defines quantum error correcting codes
39  */
40 class Codes final : public internal::Singleton<const Codes> // const Singleton
41 {
42     friend class internal::Singleton<const Codes>;
43 
44   public:
45     /**
46      * \brief Code types, add more codes here if needed
47      * \see qpp::Codes::codeword()
48      */
49     enum class Type {
50         FIVE_QUBIT,         ///< [[5,1,3]] qubit code
51         STEANE_SEVEN_QUBIT, ///< [[7,1,3]] Steane qubit code
52         SHOR_NINE_QUBIT,    ///< [[9,1,3]] Shor qubit code
53     };
54 
55   private:
56     /**
57      * \brief Default constructor
58      */
Codes()59     Codes() {} // = default; // clang++ spits the error below if defaulted:
60     //    error:
61     //    default initialization of an object of const type 'const qpp::Codes'
62     //    requires a user-provided default constructor
63 
64     /**
65      * \brief Default destructor
66      */
67     ~Codes() override = default;
68 
69   public:
70     /**
71      * \brief Returns the codeword of the specified code type
72      * \see qpp::Codes::Type
73      *
74      * \param type Code type
75      * \param i Codeword index
76      * \return \a i-th codeword  of the code \a type
77      */
codeword(Type type,idx i)78     static ket codeword(Type type, idx i) {
79         ket result;
80         switch (type) {
81             // [[5,1,3]] Five qubit code, as described in Nielsen and Chuang
82             case Type::FIVE_QUBIT:
83                 switch (i) {
84                     case 0:
85                         result =
86                             (mket({0, 0, 0, 0, 0}) + mket({1, 0, 0, 1, 0}) +
87                              mket({0, 1, 0, 0, 1}) + mket({1, 0, 1, 0, 0}) +
88                              mket({0, 1, 0, 1, 0}) - mket({1, 1, 0, 1, 1}) -
89                              mket({0, 0, 1, 1, 0}) - mket({1, 1, 0, 0, 0}) -
90                              mket({1, 1, 1, 0, 1}) - mket({0, 0, 0, 1, 1}) -
91                              mket({1, 1, 1, 1, 0}) - mket({0, 1, 1, 1, 1}) -
92                              mket({1, 0, 0, 0, 1}) - mket({0, 1, 1, 0, 0}) -
93                              mket({1, 0, 1, 1, 1}) + mket({0, 0, 1, 0, 1})) /
94                             4.;
95                         break;
96                     case 1:
97                         result =
98                             (mket({1, 1, 1, 1, 1}) + mket({0, 1, 1, 0, 1}) +
99                              mket({1, 0, 1, 1, 0}) + mket({0, 1, 0, 1, 1}) +
100                              mket({1, 0, 1, 0, 1}) - mket({0, 0, 1, 0, 0}) -
101                              mket({1, 1, 0, 0, 1}) - mket({0, 0, 1, 1, 1}) -
102                              mket({0, 0, 0, 1, 0}) - mket({1, 1, 1, 0, 0}) -
103                              mket({0, 0, 0, 0, 1}) - mket({1, 0, 0, 0, 0}) -
104                              mket({0, 1, 1, 1, 0}) - mket({1, 0, 0, 1, 1}) -
105                              mket({0, 1, 0, 0, 0}) + mket({1, 1, 0, 1, 0})) /
106                             4.;
107                         break;
108                     default:
109                         throw exception::NoCodeword("qpp::Codes::codeword()");
110                 }
111                 break;
112             // [[7,1,3]] Steane code, as described in Nielsen and Chuang
113             case Type::STEANE_SEVEN_QUBIT:
114                 switch (i) {
115                     case 0:
116                         result = (mket({0, 0, 0, 0, 0, 0, 0}) +
117                                   mket({1, 0, 1, 0, 1, 0, 1}) +
118                                   mket({0, 1, 1, 0, 0, 1, 1}) +
119                                   mket({1, 1, 0, 0, 1, 1, 0}) +
120                                   mket({0, 0, 0, 1, 1, 1, 1}) +
121                                   mket({1, 0, 1, 1, 0, 1, 0}) +
122                                   mket({0, 1, 1, 1, 1, 0, 0}) +
123                                   mket({1, 1, 0, 1, 0, 0, 1})) /
124                                  std::sqrt(8.);
125 
126                         break;
127                     case 1:
128                         result = (mket({1, 1, 1, 1, 1, 1, 1}) +
129                                   mket({0, 1, 0, 1, 0, 1, 0}) +
130                                   mket({1, 0, 0, 1, 1, 0, 0}) +
131                                   mket({0, 0, 1, 1, 0, 0, 1}) +
132                                   mket({1, 1, 1, 0, 0, 0, 0}) +
133                                   mket({0, 1, 0, 0, 1, 0, 1}) +
134                                   mket({1, 0, 0, 0, 0, 1, 1}) +
135                                   mket({0, 0, 1, 0, 1, 1, 0})) /
136                                  std::sqrt(8.);
137                         break;
138                     default:
139                         throw exception::NoCodeword("qpp::Codes::codeword()");
140                 }
141                 break;
142             // [[9,1,3]] Shor code
143             case Type::SHOR_NINE_QUBIT:
144                 ket shora = mket({0, 0, 0}) + mket({1, 1, 1});
145                 ket shorb = mket({0, 0, 0}) - mket({1, 1, 1});
146                 switch (i) {
147                     case 0:
148                         result =
149                             kron(shora, kron(shora, shora)) / std::sqrt(8.);
150                         break;
151                     case 1:
152                         result =
153                             kron(shorb, kron(shorb, shorb)) / std::sqrt(8.);
154                         break;
155                     default:
156                         throw exception::NoCodeword("qpp::Codes::codeword()");
157                 }
158         }
159 
160         return result;
161     }
162 }; /* class Codes */
163 
164 } /* namespace qpp */
165 
166 #endif /* CLASSES_CODES_HPP_ */
167