UnitaryPatterns: add the rest of the tasks from the contest (#95)
TIE fighter, Creeper, and Hessenberg matrices problems offered in Microsoft Q# Coding Contest - Winter 2019 (https://codeforces.com/contest/1116)
This commit is contained in:
Родитель
b68e90888a
Коммит
6400cb0573
|
@ -108,4 +108,131 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
XWing_Fighter_Reference(qs);
|
||||
X(Tail(qs));
|
||||
}
|
||||
|
||||
|
||||
// Task 13. TIE fighter
|
||||
|
||||
// Helper operation: decrement a little-endian register
|
||||
operation Decrement (qs : Qubit[]) : Unit {
|
||||
X(qs[0]);
|
||||
for (i in 1..Length(qs)-1) {
|
||||
(Controlled X)(qs[0..i-1], qs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper operation: antidiagonal
|
||||
operation Reflect (qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
ApplyToEachC(X, qs);
|
||||
}
|
||||
controlled auto;
|
||||
}
|
||||
|
||||
// Main operation for Task 13
|
||||
operation TIE_Fighter_Reference (qs : Qubit[]) : Unit {
|
||||
let n = Length(qs);
|
||||
X(qs[n-1]);
|
||||
(Controlled Reflect)([qs[n-1]], qs[0..(n-2)]);
|
||||
X(qs[n-1]);
|
||||
Decrement(qs[0..(n-2)]);
|
||||
H(qs[n-1]);
|
||||
(Controlled Reflect)([qs[n-1]], qs[0..(n-2)]);
|
||||
}
|
||||
|
||||
|
||||
// Task 14. Creeper
|
||||
operation Creeper_Reference (qs : Qubit[]) : Unit {
|
||||
// We observe that a Hadamard transform on 2 qubits already produces the block structure that is
|
||||
// required for the 4 "corners" of the unitary matrix. The rest of the pattern is a suitable
|
||||
// permutation of a additional block, where this block contains the Hadamard transform on 1 qubit.
|
||||
// The permutation producing the corners can be constructed from a CNOT from middle qubit to most
|
||||
// significant qubit. The permutation producing the pattern in the center can be produced by
|
||||
// applying a cyclic shift of the quantum register. This can be accomplished using a CNOT and a CCNOT.
|
||||
CNOT(qs[1], qs[2]);
|
||||
CNOT(qs[2], qs[0]);
|
||||
CCNOT(qs[0], qs[2], qs[1]);
|
||||
X(qs[2]);
|
||||
(Controlled H)([qs[2]], qs[1]);
|
||||
X(qs[2]);
|
||||
H(qs[0]);
|
||||
CNOT(qs[1], qs[2]);
|
||||
}
|
||||
|
||||
|
||||
// Task 15. Hessenberg matrices
|
||||
|
||||
// Helper function for Embedding_Perm: finds first location where bit strings differ.
|
||||
function FirstDiff (bits1 : Bool[], bits2 : Bool[]) : Int {
|
||||
for (i in 0 .. Length(bits1)-1) {
|
||||
if (bits1[i] != bits2[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Helper function for Embed_2x2_Operator: performs a Clifford to implement a base change
|
||||
// that maps basis states index1 to 111...10 and index2 to 111...11 (in big endian notation, i.e., LSB in qs[n-1])
|
||||
operation Embedding_Perm (index1 : Int, index2 : Int, qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
let n = Length(qs);
|
||||
let bits1 = BoolArrFromPositiveInt(index1, n);
|
||||
let bits2 = BoolArrFromPositiveInt(index2, n);
|
||||
// find the index of the first bit at which the bit strings are different
|
||||
let diff = FirstDiff(bits1, bits2);
|
||||
|
||||
// we care only about 2 inputs: basis state of bits1 and bits2
|
||||
|
||||
// make sure that the state corresponding to bits1 has qs[diff] set to |0⟩
|
||||
if (bits1[diff]) {
|
||||
X(qs[diff]);
|
||||
}
|
||||
|
||||
// iterate through the bit strings again, setting the final state of qubits
|
||||
for (i in 0..n-1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
// if two bits are the same, set both to 1 using X or nothing
|
||||
if (not bits1[i]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
// if two bits are different, set both to 1 using CNOT
|
||||
if (i > diff) {
|
||||
if (not bits1[i]) {
|
||||
X(qs[diff]);
|
||||
CNOT(qs[diff], qs[i]);
|
||||
X(qs[diff]);
|
||||
}
|
||||
if (not bits2[i]) {
|
||||
CNOT(qs[diff], qs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move the differing bit to the last qubit
|
||||
if (diff < n-1) {
|
||||
SWAP(qs[n-1], qs[diff]);
|
||||
}
|
||||
}
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
// Helper function: apply the 2x2 unitary operator at the sub-matrix given by indices for 2 rows/columns
|
||||
operation Embed_2x2_Operator (U : (Qubit => Unit : Controlled), index1 : Int, index2 : Int, qs : Qubit[]) : Unit {
|
||||
Embedding_Perm(index1, index2, qs);
|
||||
(Controlled U)(Most(qs), Tail(qs));
|
||||
(Adjoint Embedding_Perm)(index1, index2, qs);
|
||||
}
|
||||
|
||||
|
||||
// Putting everything together: the target pattern is produced by a sequence of controlled H gates.
|
||||
operation Hessenberg_Matrix_Reference (qs : Qubit[]) : Unit {
|
||||
let n = Length(qs);
|
||||
for (i in 2^n-2..-1..0) {
|
||||
Embed_2x2_Operator(H, i, i+1, qs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -251,4 +251,68 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
operation Rhombus (qs : Qubit[]) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 13. TIE fighter
|
||||
// Input: N qubits in an arbitrary state (2 <= N <= 5).
|
||||
// Goal: Implement a unitary transformation on N qubits that is represented by a matrix
|
||||
// with non-zero elements in the following positions:
|
||||
// - the central 2x2 sub-matrix;
|
||||
// - the diagonals of the top right and bottom left sub-matrices of size 2^(N-1)-1
|
||||
// that do not overlap with the central 2x2 sub-matrix;
|
||||
// - the anti-diagonals of the top left and bottom right sub-matrices of size 2^(N-1)-1
|
||||
// that do not overlap with the central 2x2 sub-matrix.
|
||||
// Example: For N = 3, the matrix should look as follows:
|
||||
// ..X..X..
|
||||
// .X....X.
|
||||
// X......X
|
||||
// ...XX...
|
||||
// ...XX...
|
||||
// X......X
|
||||
// .X....X.
|
||||
// ..X..X..
|
||||
operation TIE_Fighter (qs : Qubit[]) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 14. Creeper
|
||||
// Input: 3 qubits in an arbitrary state.
|
||||
// Goal: Implement a unitary transformation on 3 qubits which is represented by a matrix
|
||||
// with non-zero elements in the following pattern:
|
||||
// XX....XX
|
||||
// XX....XX
|
||||
// ...XX...
|
||||
// ...XX...
|
||||
// ..X..X..
|
||||
// ..X..X..
|
||||
// XX....XX
|
||||
// XX....XX
|
||||
operation Creeper (qs : Qubit[]) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 15. Hessenberg matrices
|
||||
// Input: N qubits in an arbitrary state (2 <= N <= 4).
|
||||
// Goal: Implement a unitary transformation on N qubits which is represented by a matrix
|
||||
// with non-zero elements forming an upper diagonal matrix plus the first subdiagonal.
|
||||
// This is called a 'Hessenberg matrix' https://en.wikipedia.org/wiki/Hessenberg_matrix.
|
||||
// Example: For N = 2, the matrix of the transformation should look as follows:
|
||||
// XXXX
|
||||
// XXXX
|
||||
// .XXX
|
||||
// ..XX
|
||||
// For N = 3, the matrix should look as follows:
|
||||
// XXXXXXXX
|
||||
// XXXXXXXX
|
||||
// .XXXXXXX
|
||||
// ..XXXXXX
|
||||
// ...XXXXX
|
||||
// ....XXXX
|
||||
// .....XXX
|
||||
// ......XX
|
||||
operation Hessenberg_Matrix (qs : Qubit[]) : Unit {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,6 +257,58 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
function TIE_Fighter_Pattern (size : Int, row : Int, col : Int) : Bool {
|
||||
let s2 = size / 2;
|
||||
return row / s2 == 0 and col / s2 == 0 and row % s2 + col % s2 == s2 - 2 or
|
||||
row / s2 == 0 and col / s2 == 1 and col % s2 - row % s2 == 1 or
|
||||
row / s2 == 1 and col / s2 == 0 and row % s2 - col % s2 == 1 or
|
||||
row / s2 == 1 and col / s2 == 1 and row % s2 + col % s2 == s2 or
|
||||
(row == s2 - 1 or row == s2) and (col == s2 - 1 or col == s2);
|
||||
}
|
||||
|
||||
|
||||
operation T13_TIE_Fighter_Test () : Unit {
|
||||
for (n in 2 .. 5) {
|
||||
AssertOperationMatrixMatchesPattern(n, TIE_Fighter, TIE_Fighter_Pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
function Creeper_Pattern (size : Int, row : Int, col : Int) : Bool {
|
||||
let A = [ [ true, true, false, false, false, false, true, true],
|
||||
[ true, true, false, false, false, false, true, true],
|
||||
[ false, false, false, true, true, false, false, false],
|
||||
[ false, false, false, true, true, false, false, false],
|
||||
[ false, false, true, false, false, true, false, false],
|
||||
[ false, false, true, false, false, true, false, false],
|
||||
[ true, true, false, false, false, false, true, true],
|
||||
[ true, true, false, false, false, false, true, true] ];
|
||||
if (size != 8) {
|
||||
return false;
|
||||
}
|
||||
return A[row][col];
|
||||
}
|
||||
|
||||
|
||||
operation T14_Creeper_Test () : Unit {
|
||||
AssertOperationMatrixMatchesPattern(3, Creeper, Creeper_Pattern);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
function Hessenberg_Matrix_Pattern (size : Int, row : Int, col : Int) : Bool {
|
||||
return (row - 1) <= col;
|
||||
}
|
||||
|
||||
|
||||
operation T15_Hessenberg_Matrix_Test () : Unit {
|
||||
for (n in 2 .. 4) {
|
||||
AssertOperationMatrixMatchesPattern(n, Hessenberg_Matrix, Hessenberg_Matrix_Pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
function GetOracleCallsCount<'T> (oracle : 'T) : Int { return 0; }
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче