The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches
Initialisation
 TEST_CASE ("initBlankState", TEST_CATEGORY)
 
 TEST_CASE ("initZeroState", TEST_CATEGORY)
 
 TEST_CASE ("initPlusState", TEST_CATEGORY)
 
 TEST_CASE ("initClassicalState", TEST_CATEGORY)
 
 TEST_CASE ("initDebugState", TEST_CATEGORY)
 
 TEST_CASE ("initRandomPureState", TEST_CATEGORY)
 
 TEST_CASE ("initRandomMixedState", TEST_CATEGORY)
 
 TEST_CASE ("initArbitraryPureState", TEST_CATEGORY)
 
 TEST_CASE ("setQuregAmps", TEST_CATEGORY)
 
 TEST_CASE ("setDensityQuregFlatAmps", TEST_CATEGORY)
 
 TEST_CASE ("setDensityQuregAmps", TEST_CATEGORY)
 
 TEST_CASE ("setQuregToRenormalized", TEST_CATEGORY)
 
 TEST_CASE ("setQuregToPauliStrSum", TEST_CATEGORY)
 
 TEST_CASE ("setQuregToWeightedSum", TEST_CATEGORY)
 
 TEST_CASE ("setQuregToMixture", TEST_CATEGORY)
 

Detailed Description

Function Documentation

◆ TEST_CASE() [1/15]

TEST_CASE ( "initArbitraryPureState" ,
TEST_CATEGORY  )

Definition at line 227 of file initialisations.cpp.

227 {
228
229 SECTION( LABEL_CORRECTNESS ) {
230
231 // works for unnormalised states
232 qvector refVec = getRandomVector(getPow2(getNumCachedQubits()));
233 qmatrix refMat = getOuterProduct(refVec, refVec);
234
235 auto apiFunc = [&](Qureg qureg) { initArbitraryPureState(qureg, refVec.data()); };
236
237 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), apiFunc, refVec); }
238 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
239 }
240
241 /// @todo input validation
242}
void initArbitraryPureState(Qureg qureg, qcomp *amps)
Definition qureg.h:49

◆ TEST_CASE() [2/15]

TEST_CASE ( "initBlankState" ,
TEST_CATEGORY  )

TESTS

Definition at line 75 of file initialisations.cpp.

75 {
76
77 SECTION( LABEL_CORRECTNESS ) {
78
79 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initBlankState, getRefStatevec()); }
80 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initBlankState, getRefDensmatr()); }
81 }
82
83 /// @todo input validation
84}
void initBlankState(Qureg qureg)

◆ TEST_CASE() [3/15]

TEST_CASE ( "initClassicalState" ,
TEST_CATEGORY  )

Definition at line 121 of file initialisations.cpp.

121 {
122
123 SECTION( LABEL_CORRECTNESS ) {
124
125 int numQubits = getNumCachedQubits();
126 int numInds = (int) getPow2(numQubits);
127 int stateInd = GENERATE_COPY( range(0,numInds) );
128
129 qvector refVec = getRefStatevec(); refVec[stateInd] = 1; // |i> = {0, ..., 1, 0, ...}
130 qmatrix refMat = getRefDensmatr(); refMat[stateInd][stateInd] = 1; // |i><i|
131
132 auto apiFunc = [&](Qureg qureg) { initClassicalState(qureg, stateInd); };
133
134 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), apiFunc, refVec); }
135 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
136 }
137
138 /// @todo input validation
139}
void initClassicalState(Qureg qureg, qindex stateInd)

◆ TEST_CASE() [4/15]

TEST_CASE ( "initDebugState" ,
TEST_CATEGORY  )

Definition at line 142 of file initialisations.cpp.

142 {
143
144 SECTION( LABEL_CORRECTNESS ) {
145
146 qvector refVec = getRefStatevec(); setToDebugState(refVec); // |debug>
147 qmatrix refMat = getRefDensmatr(); setToDebugState(refMat); // ||debug>>
148
149 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initDebugState, refVec); }
150 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initDebugState, refMat); }
151 }
152
153 /// @todo input validation
154}
void initDebugState(Qureg qureg)

◆ TEST_CASE() [5/15]

TEST_CASE ( "initPlusState" ,
TEST_CATEGORY  )

Definition at line 102 of file initialisations.cpp.

102 {
103
104 SECTION( LABEL_CORRECTNESS ) {
105
106 int numQubits = getNumCachedQubits();
107 qreal vecElem = 1. / std::sqrt(getPow2(numQubits));
108 qreal matElem = 1. / getPow2(numQubits);
109
110 qvector refVec = getConstantVector(getPow2(numQubits), vecElem); // |+> = 1/sqrt(2^N) {1, ...}
111 qmatrix refMat = getConstantMatrix(getPow2(numQubits), matElem); // |+><+| = 1/2^N {{1, ...}, ...}
112
113 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initPlusState, refVec); }
114 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initPlusState, refMat); }
115 }
116
117 /// @todo input validation
118}
void initPlusState(Qureg qureg)

◆ TEST_CASE() [6/15]

TEST_CASE ( "initRandomMixedState" ,
TEST_CATEGORY  )

Definition at line 190 of file initialisations.cpp.

190 {
191
192 SECTION( LABEL_CORRECTNESS ) {
193
194 // this test does not use reference states
195
196 GENERATE( range(0,10) );
197 int numPureStates = GENERATE( 1, 2, 10 );
198
199 auto testFunc = [&](Qureg qureg) {
200
201 initRandomMixedState(qureg, numPureStates);
202
203 /// @todo
204 /// these not-all-same-amp checks can be made much more rigorous,
205 /// by e.g. asserting distinct nodes haven't generated all the same
206 /// amplitudes (we currently observe this by eye)
207 syncQuregFromGpu(qureg);
208 REQUIRE( qureg.cpuAmps[0] != qureg.cpuAmps[1] ); // performed on all nodes
209
210 qreal prob = calcTotalProb(qureg);
211 REQUIRE_AGREE( prob, 1 );
212
213 qreal purity = calcPurity(qureg);
214 if (numPureStates == 1)
215 REQUIRE_AGREE( purity, 1 );
216 else
217 REQUIRE( purity < 1 );
218 };
219
220 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
221 }
222
223 /// @todo input validation
224}
qreal calcPurity(Qureg qureg)
qreal calcTotalProb(Qureg qureg)
void initRandomMixedState(Qureg qureg, qindex numPureStates)
void syncQuregFromGpu(Qureg qureg)
Definition qureg.cpp:416

◆ TEST_CASE() [7/15]

TEST_CASE ( "initRandomPureState" ,
TEST_CATEGORY  )

Definition at line 157 of file initialisations.cpp.

157 {
158
159 SECTION( LABEL_CORRECTNESS ) {
160
161 // this test does not use reference states
162 GENERATE( range(0,10) );
163
164 auto testFunc = [&](Qureg qureg) {
165
166 initRandomPureState(qureg);
167
168 /// @todo
169 /// these not-all-same-amp checks can be made much more rigorous,
170 /// by e.g. asserting distinct nodes haven't generated all the same
171 /// amplitudes (we currently observe this by eye)
172 syncQuregFromGpu(qureg);
173 REQUIRE( qureg.cpuAmps[0] != qureg.cpuAmps[1] );
174
175 qreal prob = calcTotalProb(qureg);
176 REQUIRE_AGREE( prob, 1 );
177
178 qreal purity = calcPurity(qureg);
179 REQUIRE_AGREE( purity, 1 );
180 };
181
182 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), testFunc); }
183 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
184 }
185
186 /// @todo input validation
187}
void initRandomPureState(Qureg qureg)

◆ TEST_CASE() [8/15]

TEST_CASE ( "initZeroState" ,
TEST_CATEGORY  )

Definition at line 87 of file initialisations.cpp.

87 {
88
89 SECTION( LABEL_CORRECTNESS ) {
90
91 qvector refVec = getRefStatevec(); refVec[0] = 1; // |0> = {1, 0...}
92 qmatrix refMat = getRefDensmatr(); refMat[0][0] = 1; // |0><0| = {{1,0...},{0...}...}
93
94 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initZeroState, refVec); }
95 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initZeroState, refMat); }
96 }
97
98 /// @todo input validation
99}
void initZeroState(Qureg qureg)

◆ TEST_CASE() [9/15]

TEST_CASE ( "setDensityQuregAmps" ,
TEST_CATEGORY  )

Definition at line 323 of file initialisations.cpp.

323 {
324
325 SECTION( LABEL_CORRECTNESS ) {
326
327 int numTotalRowsCols = getPow2(getNumCachedQubits());
328
329 // systematic iteration is WAY too slow
330 GENERATE( range(0,1000) );
331 int numSetRows = getRandomInt(1, numTotalRowsCols+1);
332 int numSetCols = getRandomInt(1, numTotalRowsCols+1);
333 int startRow = getRandomInt(0, numTotalRowsCols - numSetRows);
334 int startCol = getRandomInt(0, numTotalRowsCols - numSetCols);
335
336 // caution that amps is 'qmatrix' despite not being square
337 qmatrix amps = getRandomNonSquareMatrix(numSetRows, numSetCols);
338
339 auto testFunc = [&](Qureg qureg) {
340
341 // initialise qureg randomly
342 qmatrix refMat = getRandomMatrix(numTotalRowsCols);
343 setQuregToReference(qureg, refMat);
344
345 // API needs nested pointers
346 std::vector<qcomp*> rowPtrs(numSetRows);
347 for (size_t r=0; r<numSetRows; r++)
348 rowPtrs[r] = amps[r].data();
349
350 // overwrite a sub-matrix of refMat and Qureg
351 setSubMatrix(refMat, amps, startRow, startCol);
352 setDensityQuregAmps(qureg, startRow, startCol, rowPtrs.data(), numSetRows, numSetCols);
353
354 // check that both targeted and non-targeted amps agree
355 REQUIRE_AGREE( qureg, refMat );
356 };
357
358 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
359
360 }
361
362 /// @todo input validation
363}
void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp **amps, qindex numRows, qindex numCols)
void setSubMatrix(qmatrix &dest, qmatrix sub, size_t r, size_t c)
Definition qmatrix.cpp:203
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90

◆ TEST_CASE() [10/15]

TEST_CASE ( "setDensityQuregFlatAmps" ,
TEST_CATEGORY  )

Definition at line 285 of file initialisations.cpp.

285 {
286
287 SECTION( LABEL_CORRECTNESS ) {
288
289 int numTotalRows = getPow2(getNumCachedQubits());
290 int numTotalAmps = numTotalRows * numTotalRows;
291
292 // systematic iteration is WAY too slow
293 GENERATE( range(0,1000) );
294 int numSetAmps = getRandomInt(0, numTotalAmps + 1);
295 int startInd = getRandomInt(0, numTotalAmps - numSetAmps);
296 qvector amps = getRandomVector(numSetAmps);
297
298 auto testFunc = [&](Qureg qureg) {
299
300 // initialise qureg randomly
301 qmatrix refMat = getRandomMatrix(numTotalRows);
302 setQuregToReference(qureg, refMat);
303
304 // overwrite a contiguous region of row-major refMat, column-wise
305 refMat = getTranspose(refMat);
306 setSubMatrix(refMat, amps, startInd);
307 refMat = getTranspose(refMat);
308
309 // modify the same contiguous region of column-major qureg
310 setDensityQuregFlatAmps(qureg, startInd, amps.data(), numSetAmps);
311
312 // check that both targeted and non-targeted amps agree
313 REQUIRE_AGREE( qureg, refMat );
314 };
315
316 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
317 }
318
319 /// @todo input validation
320}
void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)

◆ TEST_CASE() [11/15]

TEST_CASE ( "setQuregAmps" ,
TEST_CATEGORY  )

Definition at line 247 of file initialisations.cpp.

247 {
248
249 SECTION( LABEL_CORRECTNESS ) {
250
251 int numTotalAmps = getPow2(getNumCachedQubits());
252 int numSetAmps = GENERATE_COPY( range(0,numTotalAmps+1) );
253
254 // Bounds-checking causes GENERATE_COPY( range(0,0) ) to fail
255 // when tests are compiled in Debug
256 int startInd = 0;
257 if (numTotalAmps - numSetAmps > 0) {
258 startInd = GENERATE_COPY( range(0,numTotalAmps-numSetAmps) );
259 }
260
261 qvector amps = getRandomVector(numSetAmps);
262
263 auto testFunc = [&](Qureg qureg) {
264
265 // initialise qureg randomly
266 qvector refVec = getRandomVector(numTotalAmps);
267 setQuregToReference(qureg, refVec);
268
269 // modify only subset of refVec amps and qureg...
270 setSubVector(refVec, amps, startInd);
271 setQuregAmps(qureg, startInd, amps.data(), numSetAmps);
272
273 // so that we simultaneously check targeted amps
274 // are modified while non-targeted are not
275 REQUIRE_AGREE( qureg, refVec );
276 };
277
278 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), testFunc); }
279 }
280
281 /// @todo input validation
282}
void setQuregAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)

◆ TEST_CASE() [12/15]

TEST_CASE ( "setQuregToMixture" ,
TEST_CATEGORY  )

Definition at line 621 of file initialisations.cpp.

621 {
622
623 SECTION( LABEL_CORRECTNESS ) {
624
625 // @todo
626 // below, we test when every inQureg is unqiue and distinct
627 // from the outQureg, and so do not test the valid scenarios of:
628 // - outQureg being among inQuregs
629 // - one or more inQuregs being repeated
630 // However, both CPU and GPU implementations are sufficiently
631 // trivial to validate by inspection (eep...)
632
633 // compile-time optimisations apply for <= 5
634 int numInQuregs = GENERATE( 1, 2, 3, 4, 5, 6, 20 );
635 CAPTURE( numInQuregs );
636
637 vector<qreal> probs = getRandomProbabilities(numInQuregs);
638
639 // we must pass identically-deployed inQureg as outQureg,
640 // which itself gets tested being each possible deployment,
641 // so we defer allocation of the inQuregs
642 vector<Qureg> inQuregs(numInQuregs);
643
644 SECTION( LABEL_DENSMATR ) {
645
646 // generate (unnormalised) input reference matrices
647 vector<qmatrix> inMatrRefs(numInQuregs);
648 for (int i=0; i<numInQuregs; i++)
649 inMatrRefs[i] = getRandomMatrix(getPow2(getNumCachedQubits()));
650
651 // compute output reference matrix
652 qmatrix outMatrRef = getZeroMatrix(getPow2(getNumCachedQubits()));
653 for (int i=0; i<numInQuregs; i++)
654 outMatrRef += probs[i] * inMatrRefs[i];
655
656 auto apiFunc = [&](Qureg outQureg) {
657
658 // prepare input quregs
659 for (int i=0; i<numInQuregs; i++) {
660 inQuregs[i] = createCloneQureg(outQureg);
661 setQuregToReference(inQuregs[i], inMatrRefs[i]);
662 }
663
664 // modify outQureg
665 setQuregToMixture(outQureg, probs.data(), inQuregs.data(), numInQuregs);
666
667 // free input quregs
668 for (int i=0; i<numInQuregs; i++)
669 destroyQureg(inQuregs[i]);
670 };
671
672 TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, outMatrRef);
673 }
674 }
675
676 SECTION( LABEL_VALIDATION ) {
677
678 // arbitrary existing qureg
679 Qureg qureg = getCachedDensmatrs().begin()->second;
680
681 SECTION( "out qureg uninitialised" ) {
682
683 // spoof uninitialised value to be sure
684 Qureg badQureg;
685 badQureg.numQubits = -123;
686
687 REQUIRE_THROWS_WITH(
688 setQuregToMixture(badQureg, nullptr, nullptr, 1),
689 ContainsSubstring("invalid Qureg") );
690 }
691
692 SECTION( "in qureg uninitialised" ) {
693
694 // set all inQureg to arbitrary existing qureg
695 int numIn = 5;
696 vector<Qureg> inQuregs(numIn, qureg);
697
698 // hide an unitialised qureg among them
699 Qureg badQureg;
700 badQureg.numQubits = -123;
701 int badInd = GENERATE_COPY( range(0,numIn) );
702 inQuregs[badInd] = badQureg;
703
704 REQUIRE_THROWS_WITH(
705 setQuregToMixture(qureg, nullptr, inQuregs.data(), numIn),
706 ContainsSubstring("invalid Qureg") );
707 }
708
709 SECTION( "out qureg is statevector" ) {
710
711 Qureg badQureg = getArbitraryCachedStatevec();
712
713 REQUIRE_THROWS_WITH(
714 setQuregToMixture(badQureg, nullptr, nullptr, 1),
715 ContainsSubstring("received a statevector") );
716 }
717
718 SECTION( "in qureg is statevector" ) {
719
720 // set all inQureg to arbitrary existing density matrix
721 int numIn = 5;
722 vector<Qureg> inQuregs(numIn, qureg);
723
724 // hide a statevector among them
725 int badInd = GENERATE_COPY( range(0,numIn) );
726 inQuregs[badInd] = getArbitraryCachedStatevec();
727
728 REQUIRE_THROWS_WITH(
729 setQuregToMixture(qureg, nullptr, inQuregs.data(), numIn),
730 ContainsSubstring("One or more Quregs were statevectors") );
731 }
732
733 SECTION( "number of quregs" ) {
734
735 int numIn = GENERATE( -1, 0 );
736
737 REQUIRE_THROWS_WITH(
738 setQuregToMixture(qureg, nullptr, nullptr, numIn),
739 ContainsSubstring("number of passed Quregs") && ContainsSubstring("is invalid") );
740 }
741
742 SECTION( "inconsistent qureg sizes" ) {
743
744 // must create new Quregs to ensure they are identically deployed
745 Qureg quregA = createCustomQureg(getNumCachedQubits(), 1,0,0,0);
746 Qureg quregB = createCustomQureg(getNumCachedQubits() + 1, 1,0,0,0);
747
748 // set all inQureg to quregA (as will be outQureg)
749 int numIn = 5;
750 vector<Qureg> inQuregs(numIn, quregA);
751
752 // set one to quregB
753 int badInd = GENERATE_COPY( range(0,numIn) );
754 inQuregs[badInd] = quregB;
755
756 REQUIRE_THROWS_WITH(
757 setQuregToMixture(quregA, nullptr, inQuregs.data(), numIn),
758 ContainsSubstring("inconsistent attributes") );
759
760 destroyQureg(quregA);
761 destroyQureg(quregB);
762 }
763
764 SECTION( "inconsistent qureg deployments" ) {
765
766 // we do not necessarily have differently-distributed/GPU Quregs at
767 // runtime, so we enumerate all deployments and test when they differ
768
769 for (auto& [label, badQureg]: getCachedDensmatrs()) {
770
771 if ((badQureg.isGpuAccelerated == qureg.isGpuAccelerated) &&
772 (badQureg.isDistributed == qureg.isDistributed))
773 continue;
774
775 // set all inQureg to qureg (as will be outQureg)
776 int numIn = 5;
777 vector<Qureg> inQuregs(numIn, qureg);
778
779 // set one to badQureg
780 int badInd = GENERATE_COPY( range(0,numIn) );
781 inQuregs[badInd] = badQureg;
782
783 REQUIRE_THROWS_WITH(
784 setQuregToMixture(qureg, nullptr, inQuregs.data(), numIn),
785 ContainsSubstring("inconsistent attributes") );
786 }
787
788 // automatically pass when there are no differing deployments
789 SUCCEED( );
790 }
791
792 SECTION( "invalid probs" ) {
793
794 // set all inQureg to arbitrary existing density matrix
795 int numIn = 5;
796 vector<Qureg> inQuregs(numIn, qureg);
797
798 // get valid probabilities then mess one up
799 int badInd = GENERATE_COPY( range(0,numIn) );
800 vector<qreal> probs = getRandomProbabilities(numIn);
801 probs[badInd] = GENERATE( -1., -0.1, 1.1, 2. );
802
803 REQUIRE_THROWS_WITH(
804 setQuregToMixture(qureg, probs.data(), inQuregs.data(), numIn),
805 ContainsSubstring("One or more given probabilities are invalid") );
806 }
807
808 SECTION( "unnormalised probs" ) {
809
810 // set all inQureg to arbitrary existing density matrix
811 int numIn = 5;
812 vector<Qureg> inQuregs(numIn, qureg);
813
814 // these illegal non-unity values assume eps < 0.1
815 qreal probSum = GENERATE( 0.9, 1.1 );
816 vector<qreal> probs(numIn, probSum / numIn);
817
818 REQUIRE_THROWS_WITH(
819 setQuregToMixture(qureg, probs.data(), inQuregs.data(), numIn),
820 ContainsSubstring("probabilities do not sum to") && ContainsSubstring("one") );
821 }
822
823 SECTION( "different number of quregs and probs") {
824
825 // relevant only to the C++ overload
826
827 qreal prob = 0;
828
829 REQUIRE_THROWS_WITH(
830 setQuregToMixture(qureg, {prob,prob}, {qureg}),
831 ContainsSubstring("different number of probabilities") );
832 }
833 }
834}
void setQuregToMixture(Qureg out, qreal *probs, Qureg *in, int numIn)
Qureg createCloneQureg(Qureg qureg)
Definition qureg.cpp:325
Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread)
Definition qureg.cpp:283
void destroyQureg(Qureg qureg)
Definition qureg.cpp:340
qmatrix getZeroMatrix(size_t dim)
Definition qmatrix.cpp:18
vector< qreal > getRandomProbabilities(int numProbs)
Definition random.cpp:160

◆ TEST_CASE() [13/15]

TEST_CASE ( "setQuregToPauliStrSum" ,
TEST_CATEGORY  )

Definition at line 397 of file initialisations.cpp.

397 {
398
399 SECTION( LABEL_CORRECTNESS ) {
400
401 GENERATE( range(0,10) );
402 int numQubits = getNumCachedQubits();
403 int numTerms = GENERATE_COPY( 1, numQubits, getPow2(2*numQubits) );
404 PauliStrSum sum = createRandomPauliStrSum(numQubits, numTerms);
405 qmatrix refMat = getMatrix(sum, numQubits);
406
407 auto apiFunc = [&](Qureg qureg) { setQuregToPauliStrSum(qureg, sum); };
408
409 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
410 }
411
412 /// @todo input validation
413}
void setQuregToPauliStrSum(Qureg qureg, PauliStrSum sum)

◆ TEST_CASE() [14/15]

TEST_CASE ( "setQuregToRenormalized" ,
TEST_CATEGORY  )

Definition at line 366 of file initialisations.cpp.

366 {
367
368 SECTION( LABEL_CORRECTNESS ) {
369
370 GENERATE( range(0,10) );
371 qindex dim = getPow2(getNumCachedQubits());
372 qvector refVec = getRandomVector(dim);
373 qmatrix refMat = getRandomMatrix(dim);
374
375 // eliminate random chance of tr(refMat)=0, triggering validation
376 if (doScalarsAgree(getTrace(refMat), 0))
377 refMat[0][0] += 1/(qreal) dim;
378
379 // [=] stores current (pre-normalised) reference objects
380 auto funcVec = [=](Qureg qureg) { setQuregToReference(qureg, refVec); setQuregToRenormalized(qureg); };
381 auto funcMat = [=](Qureg qureg) { setQuregToReference(qureg, refMat); setQuregToRenormalized(qureg); };
382
383 // setQuregToRenormalized() makes statevectors become valid
384 refVec = getNormalised(refVec);
385
386 // but it only divides density matrices by the sum of the real-elems of their diagonals
387 refMat /= getReferenceProbability(refMat);
388
389 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), funcVec, refVec); }
390 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), funcMat, refMat); }
391 }
392
393 /// @todo input validation
394}
qreal setQuregToRenormalized(Qureg qureg)

◆ TEST_CASE() [15/15]

TEST_CASE ( "setQuregToWeightedSum" ,
TEST_CATEGORY  )

Definition at line 416 of file initialisations.cpp.

416 {
417
418 SECTION( LABEL_CORRECTNESS ) {
419
420 // @todo
421 // below, we test when every inQureg is unqiue and distinct
422 // from the outQureg, and so do not test the valid scenarios of:
423 // - outQureg being among inQuregs
424 // - one or more inQuregs being repeated
425 // However, both CPU and GPU implementations are sufficiently
426 // trivial to validate by inspection (eep...)
427
428 qindex quregDim = getPow2(getNumCachedQubits());
429
430 // compile-time optimisations apply for <= 5
431 int numInQuregs = GENERATE( 1, 2, 3, 4, 5, 6, 20 );
432 CAPTURE( numInQuregs );
433
434 vector<qcomp> coeffs = getRandomVector(numInQuregs);
435
436 // we must pass identically-deployed inQureg as outQureg,
437 // which itself gets tested being each possible deployment,
438 // so we defer allocation of the inQuregs
439 vector<Qureg> inQuregs(numInQuregs);
440
441 // this function generates apiFunc in a way agnostic to
442 // whether outQureg is a statevector (inRefs are qvector)
443 // or a density matrix (inRefs are qmatrix)
444 auto apiFuncGen = [&](auto& inRefs) {
445
446 return [&](Qureg outQureg) {
447
448 // prepare input quregs
449 for (int i=0; i<numInQuregs; i++) {
450 inQuregs[i] = createCloneQureg(outQureg);
451 setQuregToReference(inQuregs[i], inRefs[i]);
452 }
453
454 // modify outQureg
455 setQuregToWeightedSum(outQureg, coeffs.data(), inQuregs.data(), numInQuregs);
456
457 // free input quregs
458 for (int i=0; i<numInQuregs; i++)
459 destroyQureg(inQuregs[i]);
460 };
461 };
462
463 SECTION( LABEL_STATEVEC ) {
464
465 // generate (unnormalised) input reference vectors
466 vector<qvector> inVecRefs(numInQuregs);
467 for (int i=0; i<numInQuregs; i++)
468 inVecRefs[i] = getRandomVector(quregDim);
469
470 // compute output reference vector
471 qvector outVecRef = getZeroVector(quregDim);
472 for (int i=0; i<numInQuregs; i++)
473 outVecRef += coeffs[i] * inVecRefs[i];
474
475 TEST_ON_CACHED_QUREGS(getCachedStatevecs(), apiFuncGen(inVecRefs), outVecRef);
476 }
477
478 SECTION( LABEL_DENSMATR ) {
479
480 // generate (unnormalised) input reference matrices
481 vector<qmatrix> inMatrRefs(numInQuregs);
482 for (int i=0; i<numInQuregs; i++)
483 inMatrRefs[i] = getRandomMatrix(quregDim);
484
485 // compute output reference matrix
486 qmatrix outMatrRef = getZeroMatrix(quregDim);
487 for (int i=0; i<numInQuregs; i++)
488 outMatrRef += coeffs[i] * inMatrRefs[i];
489
490 TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFuncGen(inMatrRefs), outMatrRef);
491 }
492 }
493
494 SECTION( LABEL_VALIDATION ) {
495
496 Qureg qureg = getArbitraryCachedStatevec();
497
498 SECTION( "out qureg uninitialised" ) {
499
500 // spoof uninitialised value to be sure
501 Qureg badQureg;
502 badQureg.numQubits = -123;
503
504 REQUIRE_THROWS_WITH(
505 setQuregToWeightedSum(badQureg, nullptr, nullptr, 1),
506 ContainsSubstring("invalid Qureg") );
507 }
508
509 SECTION( "in qureg uninitialised" ) {
510
511 // set all inQureg to arbitrary existing qureg
512 int numIn = 5;
513 vector<Qureg> inQuregs(numIn, qureg);
514
515 // hide an uninitialised qureg among them
516 Qureg badQureg;
517 badQureg.numQubits = -123;
518 int badInd = GENERATE_COPY( range(0,numIn) );
519 inQuregs[badInd] = badQureg;
520
521 REQUIRE_THROWS_WITH(
522 setQuregToWeightedSum(qureg, nullptr, inQuregs.data(), numIn),
523 ContainsSubstring("invalid Qureg") );
524 }
525
526 SECTION( "invalid number of quregs" ) {
527
528 int numIn = GENERATE( -1, 0 );
529
530 REQUIRE_THROWS_WITH(
531 setQuregToWeightedSum(qureg, nullptr, nullptr, numIn),
532 ContainsSubstring("number of passed Quregs") && ContainsSubstring("is invalid") );
533 }
534
535 SECTION( "inconsistent qureg types" ) {
536
537 // must create new Quregs to ensure they are identically deployed
538 Qureg sv = createCustomQureg(getNumCachedQubits(), 0, 0,0,0);
539 Qureg dm = createCustomQureg(getNumCachedQubits(), 1, 0,0,0);
540
541 // set all inQureg to sv (as will be outQureg)
542 int numIn = 5;
543 vector<Qureg> inQuregs(numIn, sv);
544
545 // set one to dm
546 int badInd = GENERATE_COPY( range(0,numIn) );
547 inQuregs[badInd] = dm;
548
549 REQUIRE_THROWS_WITH(
550 setQuregToWeightedSum(sv, nullptr, inQuregs.data(), numIn),
551 ContainsSubstring("inconsistent attributes") );
552
553 destroyQureg(sv);
554 destroyQureg(dm);
555 }
556
557 SECTION( "inconsistent qureg sizes" ) {
558
559 // must create new Quregs to ensure they are identically deployed
560 Qureg quregA = createCustomQureg(getNumCachedQubits(), 0,0,0,0);
561 Qureg quregB = createCustomQureg(getNumCachedQubits() + 1, 0,0,0,0);
562
563 // set all inQureg to quregA (as will be outQureg)
564 int numIn = 5;
565 vector<Qureg> inQuregs(numIn, quregA);
566
567 // set one to quregB
568 int badInd = GENERATE_COPY( range(0,numIn) );
569 inQuregs[badInd] = quregB;
570
571 REQUIRE_THROWS_WITH(
572 setQuregToWeightedSum(quregA, nullptr, inQuregs.data(), numIn),
573 ContainsSubstring("inconsistent attributes") );
574
575 destroyQureg(quregA);
576 destroyQureg(quregB);
577 }
578
579 SECTION( "inconsistent qureg deployments" ) {
580
581 // we do not necessarily have differently-distributed/GPU Quregs at
582 // runtime, so we enumerate all deployments and test when they differ
583
584 for (auto& [label, badQureg]: getCachedStatevecs()) {
585
586 if ((badQureg.isGpuAccelerated == qureg.isGpuAccelerated) &&
587 (badQureg.isDistributed == qureg.isDistributed))
588 continue;
589
590 // set all inQureg to qureg (as will be outQureg)
591 int numIn = 5;
592 vector<Qureg> inQuregs(numIn, qureg);
593
594 // set one to badQureg
595 int badInd = GENERATE_COPY( range(0,numIn) );
596 inQuregs[badInd] = badQureg;
597
598 REQUIRE_THROWS_WITH(
599 setQuregToWeightedSum(qureg, nullptr, inQuregs.data(), numIn),
600 ContainsSubstring("inconsistent attributes") );
601 }
602
603 // automatically pass when there are no differing deployments
604 SUCCEED( );
605 }
606
607 SECTION( "different number of quregs and coeffs") {
608
609 // relevant only to the C++ overload
610
611 qcomp coeff = getQcomp(0,0);
612
613 REQUIRE_THROWS_WITH(
614 setQuregToWeightedSum(qureg, {coeff,coeff}, {qureg}),
615 ContainsSubstring("different number of coefficients") );
616 }
617 }
618}
void setQuregToWeightedSum(Qureg out, qcomp *coeffs, Qureg *in, int numIn)
static qcomp getQcomp(qreal re, qreal im)
Definition types.h:91