[GraphColoring] Add tasks for triangle-free coloring (#719)

This commit is contained in:
Mariia Mykhailova 2022-01-05 11:54:18 -08:00 коммит произвёл GitHub
Родитель c921651fa4
Коммит adeaa8c9b2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 388 добавлений и 4 удалений

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

@ -263,4 +263,97 @@ namespace Quantum.Kata.GraphColoring {
return GroversAlgorithm_Reference(V, oracle);
}
}
//////////////////////////////////////////////////////////////////
// Part IV. Triangle-free coloring problem
//////////////////////////////////////////////////////////////////
// Task 4.1. Convert the list of graph edges into an adjacency matrix
function EdgesListAsAdjacencyMatrix_Reference (V : Int, edges : (Int, Int)[]) : Int[][] {
mutable adjVertices = [[-1, size = V], size = V];
for edgeInd in IndexRange(edges) {
let (v1, v2) = edges[edgeInd];
// track both directions in the adjacency matrix
set adjVertices w/= v1 <- (adjVertices[v1] w/ v2 <- edgeInd);
set adjVertices w/= v2 <- (adjVertices[v2] w/ v1 <- edgeInd);
}
return adjVertices;
}
// Task 4.2. Extract a list of triangles from an adjacency matrix
function AdjacencyMatrixAsTrianglesList_Reference (V : Int, adjacencyMatrix : Int[][]) : (Int, Int, Int)[] {
mutable triangles = [];
for v1 in 0 .. V - 1 {
for v2 in v1 + 1 .. V - 1 {
for v3 in v2 + 1 .. V - 1 {
if adjacencyMatrix[v1][v2] > -1 and adjacencyMatrix[v1][v3] > -1 and adjacencyMatrix[v2][v3] > -1 {
set triangles = triangles + [(v1, v2, v3)];
}
}
}
}
return triangles;
}
// Task 4.3. Classical verification of triangle-free coloring
function IsVertexColoringTriangleFree_Reference (V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
// Construct adjacency matrix of the graph
let adjacencyMatrix = EdgesListAsAdjacencyMatrix_Reference(V, edges);
// Enumerate all possible triangles of edges
let trianglesList = AdjacencyMatrixAsTrianglesList_Reference(V, adjacencyMatrix);
for (v1, v2, v3) in trianglesList {
if (colors[adjacencyMatrix[v1][v2]] == colors[adjacencyMatrix[v1][v3]] and
colors[adjacencyMatrix[v1][v2]] == colors[adjacencyMatrix[v2][v3]]) {
return false;
}
}
return true;
}
// Task 4.4. Oracle to check that three colors don't form a triangle
// (f(x) = 1 if at least two of three input bits are different)
operation ValidTriangleOracle_Reference (inputs : Qubit[], output : Qubit) : Unit is Adj+Ctl {
// We want to NOT mark only all 0s and all 1s - mark them and flip the output qubit
(ControlledOnInt(0, X))(inputs, output);
Controlled X(inputs, output);
X(output);
}
// Task 4.5. Oracle for verifying triangle-free edge coloring
// (f(x) = 1 if the graph edge coloring is triangle-free)
operation TriangleFreeColoringOracle_Reference (
V : Int,
edges : (Int, Int)[],
colorsRegister : Qubit[],
target : Qubit
) : Unit is Adj+Ctl {
// Construct adjacency matrix of the graph
let adjacencyMatrix = EdgesListAsAdjacencyMatrix_Reference(V, edges);
// Enumerate all possible triangles of edges
let trianglesList = AdjacencyMatrixAsTrianglesList_Reference(V, adjacencyMatrix);
// Allocate one extra qubit per triangle
let nTr = Length(trianglesList);
use aux = Qubit[nTr];
within {
for i in 0 .. nTr - 1 {
// For each triangle, form an array of qubits that holds its edge colors
let (v1, v2, v3) = trianglesList[i];
let edgeColors = [colorsRegister[adjacencyMatrix[v1][v2]],
colorsRegister[adjacencyMatrix[v1][v3]],
colorsRegister[adjacencyMatrix[v2][v3]]];
ValidTriangleOracle_Reference(edgeColors, aux[i]);
}
} apply {
// If all triangles are good, all aux qubits are 1
Controlled X(aux, target);
}
}
}

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

@ -96,6 +96,10 @@ namespace Quantum.Kata.GraphColoring {
// Part II. Vertex coloring problem
//////////////////////////////////////////////////////////////////
// The vertex graph coloring is a coloring of graph vertices which
// labels each vertex with one of the given colors so that
// no two vertices of the same color are connected by an edge.
// Task 2.1. Classical verification of vertex coloring
// Inputs:
// 1) The number of vertices in the graph V (V ≤ 6).
@ -157,6 +161,11 @@ namespace Quantum.Kata.GraphColoring {
// Part III. Weak coloring problem
//////////////////////////////////////////////////////////////////
// Weak graph coloring is a coloring of graph vertices which
// labels each vertex with one of the given colors so that
// each vertex is either isolated or is connected by an edge
// to at least one neighbor of a different color.
// Task 3.1. Determine if an edge contains the vertex
// Inputs:
// 1) An edge denoted by a tuple of integers.
@ -265,4 +274,125 @@ namespace Quantum.Kata.GraphColoring {
// ...
return [0, size = V];
}
}
//////////////////////////////////////////////////////////////////
// Part IV. Triangle-free coloring problem
//////////////////////////////////////////////////////////////////
// Triangle-free graph coloring is a coloring of graph edges which
// labels each edge with one of two colors so that no three edges
// of the same color form a triangle.
// Task 4.1. Convert the list of graph edges into an adjacency matrix
// Inputs:
// 1) The number of vertices in the graph V (V ≤ 6).
// 2) An array of E tuples of integers, representing the edges of the graph (E ≤ 12).
// Each tuple gives the indices of the start and the end vertices of the edge.
// The vertices are indexed 0 through V - 1.
// Output: A 2D array of integers representing this graph as an adjacency matrix:
// the element [i][j] should be -1 if the vertices i and j are not connected with an edge,
// or store the index of the edge if the vertices i and j are connected with an edge.
// Elements [i][i] should be -1 unless there is an edge connecting vertex i to itself.
// Example: Consider a graph with V = 3 and edges = [(0, 1), (0, 2), (1, 2)].
// The adjacency matrix for it would be
// [-1, 0, 1],
// [ 0, -1, 2],
// [ 1, 2, -1].
function EdgesListAsAdjacencyMatrix (V : Int, edges : (Int, Int)[]) : Int[][] {
// ...
return [];
}
// Task 4.2. Extract a list of triangles from an adjacency matrix
// Inputs:
// 1) The number of vertices in the graph V (V ≤ 6).
// 2) An adjacency matrix describing the graph in the format from task 4.1.
// Output: An array of 3-tuples listing all triangles in the graph,
// that is, all triplets of vertices connected by edges.
// Each of the 3-tuples should list the triangle vertices in ascending order,
// and the 3-tuples in the array should be sorted in ascending order as well.
// Example: Consider the adjacency matrix
// [-1, 0, 1],
// [ 0, -1, 2],
// [ 1, 2, -1].
// The list of triangles for it would be [(0, 1, 2)].
function AdjacencyMatrixAsTrianglesList (V : Int, adjacencyMatrix : Int[][]) : (Int, Int, Int)[] {
// ...
return [];
}
// Task 4.3. Classical verification of triangle-free coloring
// Inputs:
// 1) The number of vertices in the graph V (V ≤ 6).
// 2) An array of E tuples of integers, representing the edges of the graph (E ≤ 12).
// Each tuple gives the indices of the start and the end vertices of the edge.
// The vertices are indexed 0 through V - 1.
// 3) An array of E integers, representing the edge coloring of the graph.
// i-th element of the array is the color of the edge number i, and it is 0 or 1.
// The colors of edges in this array are given in the same order as the edges in the "edges" array.
// Output: true if the given coloring is triangle-free
// (i.e., no triangle of edges connecting 3 vertices has all three edges in the same color),
// and false otherwise.
// Example: Consider a graph with V = 3 and edges = [(0, 1), (0, 2), (1, 2)].
// Some of the valid colorings for it would be [0, 1, 0] and [-1, 5, 18].
function IsVertexColoringTriangleFree (V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
// ...
return true;
}
// Task 4.4. Oracle to check that three colors don't form a triangle
// (f(x) = 1 if at least two of three input bits are different)
// Inputs:
// 1) a 3-qubit array `inputs`,
// 2) a qubit `output`.
// Goal: Flip the output qubit if and only if at least two of the input qubits are different.
// For example, for the result of applying the operation to state (|001⟩ + |110⟩ + |111⟩) ⊗ |0⟩
// will be |001⟩ ⊗ |1⟩ + |110⟩ ⊗ |1⟩ + |111⟩ ⊗ |0⟩.
operation ValidTriangleOracle (inputs : Qubit[], output : Qubit) : Unit is Adj+Ctl {
// ...
}
// Task 4.5. Oracle for verifying triangle-free edge coloring
// (f(x) = 1 if the graph edge coloring is triangle-free)
// Inputs:
// 1) The number of vertices in the graph V (V ≤ 6).
// 2) An array of E tuples of integers "edges", representing the edges of the graph (0 ≤ E ≤ V(V-1)/2).
// Each tuple gives the indices of the start and the end vertices of the edge.
// The vertices are indexed 0 through V - 1.
// The graph is undirected, so the order of the start and the end vertices in the edge doesn't matter.
// 3) An array of E qubits "colorsRegister" that encodes the color assignments of the edges.
// Each color will be 0 or 1 (stored in 1 qubit).
// The colors of edges in this array are given in the same order as the edges in the "edges" array.
// 4) A qubit "target" in an arbitrary state.
//
// Goal: Implement a marking oracle for function f(x) = 1 if
// the coloring of the edges of the given graph described by this colors assignment is triangle-free,
// i.e., no triangle of edges connecting 3 vertices has all three edges in the same color.
//
// Example: a graph with 3 vertices and 3 edges [(0, 1), (1, 2), (2, 0)] has one triangle.
// The result of applying the operation to state (|001⟩ + |110⟩ + |111⟩)/√3 ⊗ |0⟩
// will be 1/√3|001⟩ ⊗ |1⟩ + 1/√3|110⟩ ⊗ |1⟩ + 1/√3|111⟩ ⊗ |0⟩.
// The first two terms describe triangle-free colorings,
// and the last term describes a coloring where all edges of the triangle have the same color.
//
// In this task you are not allowed to use quantum gates that use more qubits than the number of edges in the graph,
// unless there are 3 or less edges in the graph. For example, if the graph has 4 edges, you can only use 4-qubit gates or less.
// You are guaranteed that in tests that have 4 or more edges in the graph the number of triangles in the graph
// will be strictly less than the number of edges.
//
// Hint: Make use of functions and operations you've defined in previous tasks.
operation TriangleFreeColoringOracle (
V : Int,
edges : (Int, Int)[],
colorsRegister : Qubit[],
target : Qubit
) : Unit is Adj+Ctl {
// ...
}
}

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

@ -9,6 +9,8 @@
namespace Quantum.Kata.GraphColoring {
open Microsoft.Quantum.Logical;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Intrinsic;
@ -16,6 +18,7 @@ namespace Quantum.Kata.GraphColoring {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Diagnostics;
open Quantum.Kata.Utils;
@ -229,8 +232,8 @@ namespace Quantum.Kata.GraphColoring {
Message($"Testing V = {V}, edges = {edges}");
let N = 2 * V;
use (coloringRegister, target) = (Qubit[N], Qubit());
// Try all possible colorings of 4 colors on V vertices and check if they are calculated correctly.
// Hack: fix the color of the first vertex, since all colorings are agnostic to the specific colors used.
// Try all possible colorings of 4 colors on V vertices and check if they are calculated correctly.
// Hack: fix the color of the first vertex, since all colorings are agnostic to the specific colors used.
for k in 0 .. (1 <<< (N - 2)) - 1 {
// Prepare k-th coloring
let binary = [false, false] + IntAsBoolArray(k, N);
@ -387,4 +390,162 @@ namespace Quantum.Kata.GraphColoring {
Message($"Got correct coloring {coloring}");
}
}
//////////////////////////////////////////////////////////////////
// Part IV. Triangle-free coloring problem
//////////////////////////////////////////////////////////////////
@Test("QuantumSimulator")
operation T41_EdgesListAsAdjacencyMatrix () : Unit {
for (V, edges) in ExampleGraphs() {
Message($"Running on graph V = {V}, edges = {edges}");
let actualAdjMatrix = EdgesListAsAdjacencyMatrix(V, edges);
let expectedAdjMatrix = EdgesListAsAdjacencyMatrix_Reference(V, edges);
let equal = EqualA(EqualA(EqualI, _, _), actualAdjMatrix, expectedAdjMatrix);
Fact(equal, $"Got incorrect adjacency matrix {actualAdjMatrix}");
Message($"Got correct adjacency matrix");
}
}
function EqualTriplet(t1 : (Int, Int, Int), t2 : (Int, Int, Int)) : Bool {
let (p1, q1, r1) = t1;
let (p2, q2, r2) = t2;
return p1 == p2 and q1 == q2 and r1 == r2;
}
@Test("QuantumSimulator")
operation T42_AdjacencyMatrixAsTrianglesList () : Unit {
for (V, edges) in ExampleGraphs() {
Message($"Running on graph V = {V}, edges = {edges}");
let adjMatrix = EdgesListAsAdjacencyMatrix_Reference(V, edges);
let actualTrianglesList = AdjacencyMatrixAsTrianglesList(V, adjMatrix);
let expectedTrianglesList = AdjacencyMatrixAsTrianglesList_Reference(V, adjMatrix);
let equal = EqualA(EqualTriplet, actualTrianglesList, expectedTrianglesList);
Fact(equal, $"Got incorrect triangles list {actualTrianglesList}");
Message($"Got correct triangles list");
}
}
@Test("QuantumSimulator")
operation T43_IsVertexColoringTriangleFree () : Unit {
let testCases = (ExampleGraphs())[...2];
// There is only one edge coloring for a disconnected graph of 3 vertices
let coloringAndVerdicts0 = [([], true)];
// For the complete graph with 4 vertices:
let coloringAndVerdicts1 = [([0, 0, 1, 0, 1, 0], false),
([0, 0, 0, 1, 1, 1], false),
([0, 0, 1, 1, 0, 0], true)];
// For a graph with 5 vertices, 3 in a triangle and 2 separate: any coloring with the triangle of different colors
let coloringAndVerdicts2 = [([0, 0, 1, 0, 1], true),
([0, 0, 0, 1, 1], true),
([0, 1, 1, 1, 0], false)];
let fullTestCases = Zipped(testCases, [
coloringAndVerdicts0,
coloringAndVerdicts1,
coloringAndVerdicts2
]);
for (testCase, coloringAndVerdicts) in fullTestCases {
let (V, edges) = testCase;
for (coloring, expectedResult) in coloringAndVerdicts {
Fact(IsVertexColoringTriangleFree(V, edges, coloring) == expectedResult,
$"Coloring {coloring} judged {(not expectedResult) ? "" | " not"} triangle-free for graph V = {V}, edges = {edges}");
}
}
}
// Helper operation to validate oracles for things other than vertex coloring
operation VerifySingleOutputFunction(numInputs : Int, op : ((Qubit[], Qubit) => Unit is Adj+Ctl), predicate : (Int -> Bool)) : Unit {
for assignment in 0 .. 2^numInputs - 1 {
use (inputs, output) = (Qubit[numInputs], Qubit());
within {
ApplyXorInPlace(assignment, LittleEndian(inputs));
} apply {
op(inputs, output);
}
// Check that the result is expected
let actual = ResultAsBool(MResetZ(output));
let expected = predicate(assignment);
Fact(actual == expected,
$"Oracle evaluation result {actual} does not match expected {expected} for assignment {IntAsBoolArray(assignment, numInputs)}");
// Check that the inputs were not modified
Fact(MeasureInteger(LittleEndian(inputs)) == 0,
$"The input states were modified for assignment {assignment}");
}
}
function IsTriangleValid (input : Int) : Bool {
// the triangle is valid if it has at least two different bits (i.e., not all are the same)
return input > 0 and input < 7;
}
@Test("QuantumSimulator")
operation T44_ValidTriangleOracle () : Unit {
VerifySingleOutputFunction(3, ValidTriangleOracle, IsTriangleValid);
}
function ExampleGraphs_TriangleFreeColoring () : (Int, (Int, Int)[])[] {
return [
// trivial graph with no edges (no triangles)
(6, []),
// "circle" graph (no triangles)
(6, [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)]),
// complete bipartite graph K_{1,5} (no triangles)
(6, [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]),
// complete bipartite graph K_{3,3} (no triangles)
(6, [(0, 1), (0, 3), (0, 5), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4), (4, 5)]),
// complete graph with 3 edges (1 triangle)
(3, [(0, 1), (1, 2), (2, 0)]),
// disconnected graph consisting of two triangles 0-1-2 and 3-4-5
(6, [(0, 1), (4, 3), (2, 1), (5, 4), (5, 0), (2, 0)]),
// square + diagonal (two triangles)
(4, [(1, 0), (3, 2), (0, 3), (2, 1), (3, 1)]),
// square + two diagonals (four triangles)
(4, [(1, 0), (3, 2), (0, 3), (2, 1), (3, 1), (0, 2)]),
// square + two diagonals + center (4 triangles)
(5, [(0, 2), (1, 2), (3, 2), (4, 2), (0, 1), (1, 3), (4, 0), (3, 4)]),
// pyramid of 4 triangles
(6, [(2, 1), (2, 3), (1, 3), (1, 0), (1, 5), (3, 5), (3, 4), (0, 5), (5, 4)])
];
}
function BoolAsInt (a : Bool) : Int {
return a ? 1 | 0;
}
function IsVertexColoringTriangleFree_Wrapper (V : Int, edges: (Int, Int)[], colors: Int) : Bool {
let colorBools = IntAsBoolArray(colors, Length(edges));
let colorBits = Mapped(BoolAsInt, colorBools);
return IsVertexColoringTriangleFree_Reference(V, edges, colorBits);
}
@Test("QuantumSimulator")
operation T45_TriangleFreeColoringOracle () : Unit {
for (V, edges) in ExampleGraphs_TriangleFreeColoring() {
Message($"Testing {(V, edges)}");
VerifySingleOutputFunction(
Length(edges),
TriangleFreeColoringOracle(V, edges, _, _),
IsVertexColoringTriangleFree_Wrapper(V, edges, _));
}
}
}