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:
Martin Roetteler 2019-04-17 15:49:01 -07:00 коммит произвёл Mariia Mykhailova
Родитель b68e90888a
Коммит 6400cb0573
3 изменённых файлов: 243 добавлений и 0 удалений

Просмотреть файл

@ -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; }