[GraphColoring] Add tasks for triangle-free coloring (#719)
This commit is contained in:
Родитель
c921651fa4
Коммит
adeaa8c9b2
|
@ -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, _));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче