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