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/states.hpp 29 * \brief Quantum states 30 */ 31 32 #ifndef CLASSES_STATES_HPP_ 33 #define CLASSES_STATES_HPP_ 34 35 namespace qpp { 36 /** 37 * \class qpp::States 38 * \brief const Singleton class that implements most commonly used states 39 */ 40 class States final : public internal::Singleton<const States> // const Singleton 41 { 42 friend class internal::Singleton<const States>; 43 44 public: 45 // Pauli eigen-states 46 ket x0{ket::Zero(2)}; ///< Pauli Sigma-X 0-eigenstate |+> 47 ket x1{ket::Zero(2)}; ///< Pauli Sigma-X 1-eigenstate |-> 48 ket y0{ket::Zero(2)}; ///< Pauli Sigma-Y 0-eigenstate |y+> 49 ket y1{ket::Zero(2)}; ///< Pauli Sigma-Y 1-eigenstate |y-> 50 ket z0{ket::Zero(2)}; ///< Pauli Sigma-Z 0-eigenstate |0> 51 ket z1{ket::Zero(2)}; ///< Pauli Sigma-Z 1-eigenstate |1> 52 53 // projectors onto Pauli eigen-states 54 cmat px0{cmat::Zero(2, 2)}; 55 ///< Projector onto the Pauli Sigma-X 0-eigenstate |+><+| 56 cmat px1{cmat::Zero(2, 2)}; 57 ///< Projector onto the Pauli Sigma-X 1-eigenstate |-><-| 58 cmat py0{cmat::Zero(2, 2)}; 59 ///< Projector onto the Pauli Sigma-Y 0-eigenstate |y+><y+| 60 cmat py1{cmat::Zero(2, 2)}; 61 ///< Projector onto the Pauli Sigma-Y 1-eigenstate |y-><y-| 62 cmat pz0{cmat::Zero(2, 2)}; 63 ///< Projector onto the Pauli Sigma-Z 0-eigenstate |0><0| 64 cmat pz1{cmat::Zero(2, 2)}; 65 ///< Projector onto the Pauli Sigma-Z 1-eigenstate |1><1| 66 67 // Bell states 68 ket b00{ket::Zero(4)}; 69 ///< Bell-00 state, as described in Nielsen and Chuang 70 ket b01{ket::Zero(4)}; 71 ///< Bell-01 state, as described in Nielsen and Chuang 72 ket b10{ket::Zero(4)}; 73 ///< Bell-10 state, as described in Nielsen and Chuang 74 ket b11{ket::Zero(4)}; 75 ///< Bell-11 state, as described in Nielsen and Chuang 76 77 // projectors onto Bell states 78 cmat pb00{cmat::Zero(4, 4)}; ///< Projector onto the Bell-00 state 79 cmat pb01{cmat::Zero(4, 4)}; ///< Projector onto the Bell-01 state 80 cmat pb10{cmat::Zero(4, 4)}; ///< Projector onto the Bell-10 state 81 cmat pb11{cmat::Zero(4, 4)}; ///< Projector onto the Bell-11 state 82 83 // W and GHZ states 84 ket GHZ{ket::Zero(8)}; ///< GHZ state 85 ket W{ket::Zero(8)}; ///< W state 86 87 // projectors onto GHZ and W 88 cmat pGHZ{cmat::Zero(8, 8)}; ///< Projector onto the GHZ state 89 cmat pW{cmat::Zero(8, 8)}; ///< Projector onto the W state 90 91 /** 92 * \brief Maximally entangled state of 2 qudits 93 * 94 * \param d Subsystem dimensions 95 * \return Maximally entangled state 96 * \f$\frac{1}{\sqrt{d}}\sum_{j=0}^{d-1}|jj\rangle\f$ of 2 qudits 97 */ mes(idx d=2) const98 ket mes(idx d = 2) const { 99 // EXCEPTION CHECKS 100 101 // check valid dims 102 if (d == 0) 103 throw exception::DimsInvalid("qpp::States::mes()"); 104 // END EXCEPTION CHECKS 105 106 ket psi = mket({0, 0}, {d, d}); 107 for (idx i = 1; i < d; ++i) { 108 psi += mket({i, i}, {d, d}); 109 } 110 111 return psi / std::sqrt(d); 112 } 113 114 /** 115 * \brief Zero state of \a n qudits 116 * \see qpp::States::one() 117 * 118 * \param n Positive integer, 1 by default 119 * \param d Subsystem dimensions 120 * \return Zero state \f$|0\rangle^{\otimes n}\f$ of \a n qudits 121 */ zero(idx n=1,idx d=2) const122 ket zero(idx n = 1, idx d = 2) const { 123 // EXCEPTION CHECKS 124 125 // check out of range 126 if (n == 0) 127 throw exception::OutOfRange("qpp::States::zero()"); 128 // check valid dims 129 if (d == 0) 130 throw exception::DimsInvalid("qpp::States::zero()"); 131 // END EXCEPTION CHECKS 132 133 idx D = static_cast<idx>(std::llround(std::pow(d, n))); 134 ket result = ket::Zero(D); 135 result(0) = 1; 136 137 return result; 138 } 139 140 /** 141 * \brief One state of \a n qudits 142 * \see qpp::States::zero() 143 * 144 * \param n Positive integer, 1 by default 145 * \param d Subsystem dimensions 146 * \return One state \f$|1\rangle^{\otimes n}\f$ of \a n qudits 147 */ one(idx n=1,idx d=2) const148 ket one(idx n = 1, idx d = 2) const { 149 // EXCEPTION CHECKS 150 151 // check out of range 152 if (n == 0) 153 throw exception::OutOfRange("qpp::States::one()"); 154 // check valid dims 155 if (d == 0) 156 throw exception::DimsInvalid("qpp::States::one()"); 157 // END EXCEPTION CHECKS 158 159 ket result = ket::Zero(static_cast<ket::Index>(std::pow(d, n))); 160 result(multiidx2n(std::vector<idx>(n, 1), std::vector<idx>(n, d))) = 1; 161 162 return result; 163 } 164 165 /** 166 * \brief \f$|j\rangle^{\otimes n}\f$ state of \a n qudits 167 * \see qpp::States::j() 168 * 169 * \param j Non-negative integer 170 * \param n Positive integer, 1 by default 171 * \param d Subsystem dimensions 172 * \return \f$|j\rangle^{\otimes n}\f$ state of \a n qudits 173 */ jn(idx j,idx n=1,idx d=2) const174 ket jn(idx j, idx n = 1, idx d = 2) const { 175 // EXCEPTION CHECKS 176 177 // check out of range 178 if (n == 0) 179 throw exception::OutOfRange("qpp::States::jn()"); 180 // check valid subsystem 181 if (j >= d) 182 throw exception::SubsysMismatchDims("qpp::States::jn()"); 183 184 // check valid dims 185 if (d == 0) 186 throw exception::DimsInvalid("qpp::States::jn()"); 187 // END EXCEPTION CHECKS 188 189 ket result = ket::Zero(static_cast<ket::Index>(std::pow(d, n))); 190 result(multiidx2n(std::vector<idx>(n, j), std::vector<idx>(n, d))) = 1; 191 192 return result; 193 } 194 195 /** 196 * \brief \f$|j\rangle\f$ computational basis state of a single qudit 197 * \see qpp::States::jn() 198 * 199 * \param j Non-negative integer 200 * \param D System dimension 201 * \return \f$|j\rangle\f$ computational basis state of a single qudit 202 */ j(idx j,idx D=2) const203 ket j(idx j, idx D = 2) const { 204 // EXCEPTION CHECKS 205 206 // check valid subsystem 207 if (j >= D) 208 throw exception::SubsysMismatchDims("qpp::States::j()"); 209 210 // check valid dims 211 if (D == 0) 212 throw exception::DimsInvalid("qpp::States::j()"); 213 // END EXCEPTION CHECKS 214 215 ket result = ket::Zero(D); 216 result(j) = 1; 217 218 return result; 219 } 220 221 /** 222 * \brief Plus state of \a n qubits 223 * \see qpp::States::minus() 224 * 225 * \param n Positive integer, 1 by default 226 * \return Plus state \f$|+\rangle^{\otimes n}\f$ of \a n qubits 227 */ plus(idx n=1) const228 ket plus(idx n = 1) const { 229 // EXCEPTION CHECKS 230 231 // check out of range 232 if (n == 0) 233 throw exception::OutOfRange("qpp::States::plus()"); 234 // END EXCEPTION CHECKS 235 236 idx D = static_cast<idx>(std::llround(std::pow(2, n))); 237 ket result = ket::Ones(D); 238 239 return result / std::sqrt(D); 240 } 241 242 /** 243 * \brief Minus state of \a n qubits 244 * \see qpp::States::plus() 245 * 246 * \param n Positive integer, 1 by default 247 * \return Minus state \f$|-\rangle^{\otimes n}\f$ of \a n qubits 248 */ minus(idx n=1) const249 ket minus(idx n = 1) const { 250 // EXCEPTION CHECKS 251 252 // check out of range 253 if (n == 0) 254 throw exception::OutOfRange("qpp::States::minus()"); 255 // END EXCEPTION CHECKS 256 257 return kronpow(x1, n); 258 } 259 260 private: 261 /** 262 * Initialize the states 263 */ States()264 States() { 265 // initialize 266 x0 << 1 / std::sqrt(2.), 1 / std::sqrt(2.); 267 x1 << 1 / std::sqrt(2.), -1 / std::sqrt(2.); 268 y0 << 1 / std::sqrt(2.), 1_i / std::sqrt(2.); 269 y1 << 1 / std::sqrt(2.), -1_i / std::sqrt(2.); 270 z0 << 1, 0; 271 z1 << 0, 1; 272 px0 = x0 * x0.adjoint(); 273 px1 = x1 * x1.adjoint(); 274 py0 = y0 * y0.adjoint(); 275 py1 = y1 * y1.adjoint(); 276 pz0 = z0 * z0.adjoint(); 277 pz1 = z1 * z1.adjoint(); 278 279 // Bell states, as described in Nielsen and Chuang 280 // |ij> -> |b_{ij}> by the CNOT*(H x Id) circuit 281 282 b00 << 1 / std::sqrt(2.), 0, 0, 1 / std::sqrt(2.); 283 // (|00> + |11>) / sqrt(2) 284 b01 << 0, 1 / std::sqrt(2.), 1 / std::sqrt(2.), 0; 285 // (|01> + |10>) / sqrt(2) 286 b10 << 1 / std::sqrt(2.), 0, 0, -1 / std::sqrt(2.); 287 // (|00> - |11>) / sqrt(2) 288 b11 << 0, 1 / std::sqrt(2.), -1 / std::sqrt(2.), 0; 289 // (|01> - |10>) / sqrt(2) 290 291 pb00 = b00 * b00.adjoint(); 292 pb01 = b01 * b01.adjoint(); 293 pb10 = b10 * b10.adjoint(); 294 pb11 = b11 * b11.adjoint(); 295 296 GHZ << 1, 0, 0, 0, 0, 0, 0, 1; 297 GHZ = GHZ / std::sqrt(2.); 298 W << 0, 1, 1, 0, 1, 0, 0, 0; 299 W = W / std::sqrt(3.); 300 301 pGHZ = GHZ * GHZ.adjoint(); 302 pW = W * W.adjoint(); 303 } 304 305 /** 306 * \brief Default destructor 307 */ 308 ~States() override = default; 309 }; /* class States */ 310 311 } /* namespace qpp */ 312 313 #endif /* CLASSES_STATES_HPP_ */ 314