Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ORNL Quantum Computing Institute
xacc
Commits
fbdc2091
Commit
fbdc2091
authored
Jul 11, 2017
by
Mccaskey, Alex
Browse files
Adding implementation of DWQMICompiler
parent
497af36f
Changes
12
Hide whitespace changes
Inline
Side-by-side
impls/dwave/DWQMICompiler.cpp
View file @
fbdc2091
...
...
@@ -32,6 +32,7 @@
#include
<boost/algorithm/string.hpp>
#include
"DWQMICompiler.hpp"
#include
"DWKernel.hpp"
#include
"RuntimeOptions.hpp"
namespace
xacc
{
...
...
@@ -43,15 +44,16 @@ DWQMICompiler::DWQMICompiler() {
std
::
shared_ptr
<
IR
>
DWQMICompiler
::
compile
(
const
std
::
string
&
src
,
std
::
shared_ptr
<
Accelerator
>
acc
)
{
auto
runtimeOptions
=
RuntimeOptions
::
instance
();
auto
hardwareGraph
=
acc
->
getAcceleratorConnectivity
();
auto
dwKernel
=
std
::
make_shared
<
DWKernel
>
();
std
::
set
<
int
>
qubits
;
std
::
vector
<
std
::
shared_ptr
<
DWQMI
>>
instructions
;
int
nHardwareVerts
=
hardwareGraph
->
order
();
// Set the Kernel Source code
kernelSource
=
src
;
return
std
::
make_shared
<
DWIR
>
();
}
std
::
shared_ptr
<
IR
>
DWQMICompiler
::
compile
(
const
std
::
string
&
src
)
{
kernelSource
=
src
;
// Here we expect we have a kernel, only one kernel,
// and that it is just machine level instructions
...
...
@@ -60,41 +62,131 @@ std::shared_ptr<IR> DWQMICompiler::compile(const std::string& src) {
// First off, split the string into lines
std
::
vector
<
std
::
string
>
lines
;
boost
::
split
(
lines
,
src
,
boost
::
is_any_of
(
"
\n
"
));
auto
firstCodeLine
=
lines
.
begin
()
+
1
;
auto
lastCodeLine
=
lines
.
end
()
-
1
;
std
::
vector
<
std
::
string
>
qmiStrVec
(
firstCodeLine
,
lastCodeLine
);
auto
dwKernel
=
std
::
make_shared
<
DWKernel
>
();
// Loop over the lines to create DWQMI
for
(
auto
qmi
:
qmiStrVec
)
{
std
::
cout
<<
"LINE: "
<<
qmi
<<
"
\n
"
;
boost
::
trim
(
qmi
);
if
(
!
qmi
.
empty
())
{
std
::
vector
<
std
::
string
>
splitOnSpaces
;
boost
::
split
(
splitOnSpaces
,
qmi
,
boost
::
is_any_of
(
" "
));
auto
qbit1
=
std
::
stoi
(
splitOnSpaces
[
0
]);
auto
qbit2
=
std
::
stoi
(
splitOnSpaces
[
1
]);
auto
weight
=
std
::
stod
(
splitOnSpaces
[
2
]);
qubits
.
insert
(
qbit1
);
qubits
.
insert
(
qbit2
);
instructions
.
emplace_back
(
std
::
make_shared
<
DWQMI
>
(
qbit1
,
qbit2
,
weight
));
}
}
auto
dwqmi
=
std
::
make_shared
<
DWQMI
>
(
qbit1
,
qbit2
,
weight
);
dwKernel
->
addInstruction
(
dwqmi
);
// Create a graph representation of the problem
auto
problemGraph
=
std
::
make_shared
<
DWGraph
>
(
qubits
.
size
());
for
(
auto
inst
:
instructions
)
{
auto
qbit1
=
inst
->
bits
()[
0
];
auto
qbit2
=
inst
->
bits
()[
1
];
double
weightOrBias
=
boost
::
get
<
double
>
(
inst
->
getParameter
(
0
));
if
(
qbit1
==
qbit2
)
{
problemGraph
->
setVertexProperties
(
qbit1
,
weightOrBias
);
}
else
{
problemGraph
->
addEdge
(
qbit1
,
qbit2
,
weightOrBias
);
}
}
// Get an embedding algorithm to execute
if
(
!
runtimeOptions
->
exists
(
"dwave-embedding"
))
{
// For now, this is an error
XACCError
(
"You must specify an embedding algorithm"
);
}
auto
algoStr
=
(
*
runtimeOptions
)[
"dwave-embedding"
];
auto
embeddingAlgorithm
=
EmbeddingAlgorithmRegistry
::
instance
()
->
create
(
algoStr
);
// Compute the minor graph embedding
auto
embedding
=
embeddingAlgorithm
->
embed
(
problemGraph
,
hardwareGraph
);
auto
countEdgesBetweenSubTrees
=
[
&
](
std
::
list
<
int
>
Ti
,
std
::
list
<
int
>
Tj
)
->
int
{
int
nEdges
=
0
;
for
(
auto
i
:
Ti
)
{
for
(
auto
j
:
Tj
)
{
if
(
hardwareGraph
->
edgeExists
(
i
,
j
))
{
nEdges
++
;
}
}
}
return
nEdges
;
};
auto
subTreeContains
=
[](
std
::
list
<
int
>
tree
,
int
i
)
->
bool
{
return
std
::
find
(
tree
.
begin
(),
tree
.
end
(),
i
)
!=
tree
.
end
();
};
// Setup the hardware bias values
for
(
auto
&
embKv
:
embedding
)
{
auto
probVert
=
embKv
.
first
;
auto
hardwareMapping
=
embKv
.
second
;
auto
newBias
=
std
::
get
<
0
>
(
problemGraph
->
getVertexProperties
(
probVert
))
/
hardwareMapping
.
size
();
for
(
auto
h
:
hardwareMapping
)
{
auto
embeddedInst
=
std
::
make_shared
<
DWQMI
>
(
h
,
h
,
newBias
);
dwKernel
->
addInstruction
(
embeddedInst
);
}
}
auto
ir
=
std
::
make_shared
<
DWIR
>
();
std
::
cout
<<
"NHARDWARE: "
<<
nHardwareVerts
<<
", "
<<
problemGraph
->
order
()
<<
"
\n
"
;
for
(
int
i
=
0
;
i
<
nHardwareVerts
;
i
++
)
{
for
(
int
j
=
0
;
j
<
nHardwareVerts
;
j
++
)
{
if
(
hardwareGraph
->
edgeExists
(
i
,
j
)
&&
i
<
j
&&
i
!=
j
)
{
for
(
int
pi
=
0
;
pi
<
problemGraph
->
order
();
pi
++
)
{
for
(
int
pj
=
0
;
pj
<
problemGraph
->
order
();
pj
++
)
{
auto
Ti
=
embedding
[
pi
];
auto
Tj
=
embedding
[
pj
];
if
(
subTreeContains
(
Ti
,
i
)
&&
subTreeContains
(
Tj
,
j
))
{
double
newWeight
=
0.0
;
if
(
pi
!=
pj
)
{
newWeight
=
problemGraph
->
getEdgeWeight
(
pi
,
pj
)
/
countEdgesBetweenSubTrees
(
Ti
,
Tj
);
}
else
{
// ferro-magnetic coupling parameter that ensures that physical
// qubits representing one logical qubit remain highly correlated.
for
(
auto
neighbor
:
problemGraph
->
getNeighborList
(
pi
))
{
newWeight
+=
std
::
fabs
(
problemGraph
->
getEdgeWeight
(
pi
,
neighbor
));
}
newWeight
=
std
::
get
<
0
>
(
problemGraph
->
getVertexProperties
(
pi
))
+
newWeight
-
1.0
;
}
std
::
cout
<<
"Adding a Edge Instruction.
\n
"
;
auto
embeddedInst
=
std
::
make_shared
<
DWQMI
>
(
i
,
j
,
newWeight
);
dwKernel
->
addInstruction
(
embeddedInst
);
}
// else {
// std::cout << "SUBTREE DID NOT CONTAIN: " << i << " and " << j << "\n";
// }
}
}
}
else
{
std
::
cout
<<
"Edge did not exist between "
<<
i
<<
", "
<<
j
<<
"
\n
"
;
}
}
}
// ir->addKernel(ir);
auto
ir
=
std
::
make_shared
<
DWIR
>
();
ir
->
addKernel
(
dwKernel
);
return
ir
;
}
std
::
shared_ptr
<
IR
>
DWQMICompiler
::
compile
(
const
std
::
string
&
src
)
{
XACCError
(
"Cannot compile D-Wave program without "
"information about Accelerator connectivity."
);
}
}
...
...
impls/dwave/DWQMICompiler.hpp
View file @
fbdc2091
...
...
@@ -34,6 +34,8 @@
#include
"Compiler.hpp"
#include
"Utils.hpp"
#include
"DWIR.hpp"
#include
"DWGraph.hpp"
#include
"EmbeddingAlgorithm.hpp"
namespace
xacc
{
...
...
@@ -66,6 +68,14 @@ public:
return
"dwave-qmi"
;
}
virtual
std
::
shared_ptr
<
options_description
>
getOptions
()
{
auto
desc
=
std
::
make_shared
<
options_description
>
(
"D-Wave QMI Compiler Options"
);
desc
->
add_options
()(
"dwave-embedding"
,
value
<
std
::
string
>
(),
"Provide the name of the Embedding Algorithm to use during compilation."
);
return
desc
;
}
/**
* Register this Compiler with the framework.
*/
...
...
@@ -78,6 +88,7 @@ public:
std
::
shared_ptr
<
Function
>
function
)
{
XACCError
(
"DWQMICompiler::translate - Method not implemented"
);
};
/**
* The destructor
*/
...
...
impls/dwave/tests/DWQMICompilerTester.cpp
View file @
fbdc2091
...
...
@@ -51,22 +51,101 @@ struct F {
std
::
shared_ptr
<
xacc
::
Compiler
>
compiler
;
};
class
FakeDWAcc
:
public
xacc
::
Accelerator
{
public:
virtual
std
::
shared_ptr
<
xacc
::
AcceleratorGraph
>
getAcceleratorConnectivity
()
{
return
K44Bipartite
().
getAcceleratorGraph
();
}
virtual
xacc
::
AcceleratorType
getType
()
{
return
xacc
::
AcceleratorType
::
qpu_aqc
;
}
virtual
bool
isValidBufferSize
(
const
int
nBits
)
{
return
true
;
}
virtual
std
::
vector
<
xacc
::
IRTransformation
>
getIRTransformations
()
{
};
/**
* Execute the provided XACC IR Function on the provided AcceleratorBuffer.
*
* @param buffer The buffer of bits this Accelerator should operate on.
* @param function The kernel to execute.
*/
virtual
void
execute
(
std
::
shared_ptr
<
xacc
::
AcceleratorBuffer
>
buffer
,
const
std
::
shared_ptr
<
xacc
::
Function
>
function
)
{
}
/**
* Create, store, and return an AcceleratorBuffer with the given
* variable id string and of the given number of bits.
* The string id serves as a unique identifier
* for future lookups and reuse of the AcceleratorBuffer.
*
* @param varId The variable name of the created buffer
* @param size The number of bits in the created buffer
* @return buffer The buffer instance created.
*/
virtual
std
::
shared_ptr
<
xacc
::
AcceleratorBuffer
>
createBuffer
(
const
std
::
string
&
varId
,
const
int
size
)
{
}
};
class
FakeEmbedding
:
public
EmbeddingAlgorithm
{
public:
virtual
std
::
map
<
int
,
std
::
list
<
int
>>
embed
(
std
::
shared_ptr
<
DWGraph
>
problem
,
std
::
shared_ptr
<
xacc
::
AcceleratorGraph
>
hardware
,
std
::
map
<
std
::
string
,
std
::
string
>
params
=
std
::
map
<
std
::
string
,
std
::
string
>
())
override
{
std
::
map
<
int
,
std
::
list
<
int
>>
embedding
;
embedding
.
insert
(
std
::
make_pair
(
0
,
std
::
list
<
int
>
{
0
,
4
}));
embedding
.
insert
(
std
::
make_pair
(
1
,
std
::
list
<
int
>
{
1
}));
embedding
.
insert
(
std
::
make_pair
(
2
,
std
::
list
<
int
>
{
5
}));
return
embedding
;
}
/**
* Return the name of this Embedding Algorithm
* @return
*/
virtual
std
::
string
name
()
{
return
"fake-embedding"
;
}
};
//____________________________________________________________________________//
BOOST_FIXTURE_TEST_SUITE
(
s
,
F
)
BOOST_AUTO_TEST_CASE
(
checkSimpleCompile
)
{
EmbeddingAlgorithmRegistry
::
instance
()
->
add
(
FakeEmbedding
().
name
(),
[]()
{
return
std
::
make_shared
<
FakeEmbedding
>
();
});
const
std
::
string
simpleQMI
=
"__qpu__ dwaveKernel() {
\n
"
" 0 0 0.98
\n
"
" 1 1 .33
\n
"
" 2 2 .44
\n
"
" 0 1 .22
\n
"
" 0 2 .55
\n
"
" 1 2 .11
\n
"
"}"
;
auto
ir
=
compiler
->
compile
(
simpleQMI
);
auto
options
=
xacc
::
RuntimeOptions
::
instance
();
options
->
insert
(
std
::
make_pair
(
"dwave-embedding"
,
"fake-embedding"
));
auto
acc
=
std
::
make_shared
<
FakeDWAcc
>
();
auto
ir
=
compiler
->
compile
(
simpleQMI
,
acc
);
std
::
cout
<<
"STR:
\n
"
<<
ir
->
getKernel
(
"dw-kernel"
)
->
toString
(
""
)
<<
"
\n
"
;
}
...
...
quantum/aqc/compiler/EmbeddingAlgorithm.hpp
View file @
fbdc2091
...
...
@@ -38,28 +38,11 @@
#include
<string>
#include
"Utils.hpp"
#include
"Registry.hpp"
#include
"Graph.hpp"
#include
"
DW
Graph.hpp"
namespace
xacc
{
namespace
quantum
{
/**
* The DWaveVertex is a subclass of the XACCVertex that
* keeps track of one vertex parameter - the qubit
* bias parameter. XACCVertex already keeps track
* of edge weights.
*/
class
DWaveVertex
:
public
XACCVertex
<
double
>
{
public:
DWaveVertex
()
:
XACCVertex
()
{
propertyNames
[
0
]
=
"bias"
;
}
};
// Alias for Graphs of DWave Vertices
using
DWaveGraph
=
Graph
<
DWaveVertex
>
;
/**
* The EmbeddingAlgorithm class provides an interface
* for minor graph embedding algorithms.
...
...
@@ -89,8 +72,8 @@ public:
* @param params Any key-value string parameters to influence the algorithm.
* @return embedding A mapping of problem vertex indices to the list of hardware vertices they map to
*/
virtual
std
::
map
<
int
,
std
::
list
<
int
>>
embed
(
std
::
shared_ptr
<
DW
ave
Graph
>
problem
,
std
::
shared_ptr
<
DWave
Graph
>
hardware
,
virtual
std
::
map
<
int
,
std
::
list
<
int
>>
embed
(
std
::
shared_ptr
<
DWGraph
>
problem
,
std
::
shared_ptr
<
Accelerator
Graph
>
hardware
,
std
::
map
<
std
::
string
,
std
::
string
>
params
=
std
::
map
<
std
::
string
,
std
::
string
>
())
=
0
;
...
...
quantum/aqc/ir/DWGraph.hpp
0 → 100644
View file @
fbdc2091
/*
* DWGraph.hpp
*
* Created on: Jul 11, 2017
* Author: aqw
*/
#ifndef QUANTUM_AQC_IR_DWGRAPH_HPP_
#define QUANTUM_AQC_IR_DWGRAPH_HPP_
#include
"Graph.hpp"
namespace
xacc
{
namespace
quantum
{
/**
* The DWVertex is a subclass of the XACCVertex that
* keeps track of one vertex parameter - the qubit
* bias parameter. XACCVertex already keeps track
* of edge weights.
*/
class
DWVertex
:
public
XACCVertex
<
double
>
{
public:
DWVertex
()
:
XACCVertex
()
{
propertyNames
[
0
]
=
"bias"
;
}
};
// Alias for Graphs of DWave Vertices
class
DWGraph
:
public
Graph
<
DWVertex
>
{
public:
DWGraph
(
const
int
nVertices
)
:
Graph
(
nVertices
)
{
}
std
::
shared_ptr
<
AcceleratorGraph
>
getAcceleratorGraph
()
{
auto
retGraph
=
std
::
make_shared
<
AcceleratorGraph
>
(
order
());
for
(
int
i
=
0
;
i
<
order
();
i
++
)
{
for
(
int
j
=
0
;
j
<
order
();
j
++
)
{
if
(
i
<
j
)
{
addEdge
(
i
,
j
);
}
}
}
return
retGraph
;
}
virtual
~
DWGraph
()
{}
};
class
K44Bipartite
:
public
DWGraph
{
public:
K44Bipartite
()
:
DWGraph
(
8
)
{
addEdge
(
0
,
4
);
addEdge
(
0
,
5
);
addEdge
(
0
,
6
);
addEdge
(
0
,
7
);
addEdge
(
1
,
4
);
addEdge
(
1
,
5
);
addEdge
(
1
,
6
);
addEdge
(
1
,
7
);
addEdge
(
2
,
4
);
addEdge
(
2
,
5
);
addEdge
(
2
,
6
);
addEdge
(
2
,
7
);
addEdge
(
3
,
4
);
addEdge
(
3
,
5
);
addEdge
(
3
,
6
);
addEdge
(
3
,
7
);
}
virtual
~
K44Bipartite
()
{}
};
class
CompleteGraph
:
public
DWGraph
{
public:
CompleteGraph
(
int
nVertices
)
:
DWGraph
(
nVertices
)
{
for
(
int
i
=
0
;
i
<
nVertices
;
i
++
)
{
for
(
int
j
=
0
;
j
<
nVertices
;
j
++
)
{
if
(
i
<
j
)
{
addEdge
(
i
,
j
);
}
}
}
}
virtual
~
CompleteGraph
()
{}
};
class
Chimera
:
public
DWGraph
{
public:
Chimera
(
int
gridSize
)
:
DWGraph
(
8
*
gridSize
*
gridSize
)
{
// We are going to assign a tuple of ints to each vertex
std
::
map
<
std
::
tuple
<
int
,
int
,
int
,
int
>
,
int
>
vertexTuples
;
int
i
,
j
,
k
,
l
,
v
=
0
;
// Loop through the list of vertices and give
// them the correct 4-tuple: (i,j) is unit cell in
// the chimera grid, (k,l) is vertex in unit cell, k = 0-3,
// l = 0,1 (left, right of bipartite graph)
for
(
i
=
0
;
i
<
gridSize
;
i
++
)
{
for
(
j
=
0
;
j
<
gridSize
;
j
++
)
{
for
(
l
=
0
;
l
<
2
;
l
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
vertexTuples
.
insert
(
std
::
make_pair
(
std
::
make_tuple
(
i
,
j
,
k
,
l
),
v
));
v
++
;
}
}
}
}
// Setup edges within each cell
for
(
i
=
0
;
i
<
gridSize
;
i
++
)
{
for
(
j
=
0
;
j
<
gridSize
;
j
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
for
(
int
k2
=
0
;
k2
<
4
;
k2
++
)
{
int
v1
=
vertexTuples
[
std
::
make_tuple
(
i
,
j
,
k
,
0
)];
int
v2
=
vertexTuples
[
std
::
make_tuple
(
i
,
j
,
k2
,
1
)];
addEdge
(
v1
,
v2
);
}
}
}
}
// Setup edges between cells
for
(
i
=
0
;
i
<
gridSize
-
1
;
i
++
)
{
for
(
j
=
0
;
j
<
gridSize
;
j
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
int
v1
=
vertexTuples
[
std
::
make_tuple
(
i
,
j
,
k
,
0
)];
int
v2
=
vertexTuples
[
std
::
make_tuple
(
i
+
1
,
j
,
k
,
0
)];
addEdge
(
v1
,
v2
);
}
}
}
for
(
i
=
0
;
i
<
gridSize
;
i
++
)
{
for
(
j
=
0
;
j
<
gridSize
-
1
;
j
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
int
v1
=
vertexTuples
[
std
::
make_tuple
(
i
,
j
,
k
,
1
)];
int
v2
=
vertexTuples
[
std
::
make_tuple
(
i
,
j
+
1
,
k
,
1
)];
addEdge
(
v1
,
v2
);
}
}
}
}
virtual
~
Chimera
()
{}
};
}
}
#endif
quantum/aqc/ir/DWIR.hpp
View file @
fbdc2091
...
...
@@ -2,23 +2,11 @@
#define QUANTUM_AQC_IR_DWIR_HPP_
#include
"IR.hpp"
#include
"Graph.hpp"
#include
"
DW
Graph.hpp"
namespace
xacc
{
namespace
quantum
{
using
DWVertex
=
XACCVertex
<
double
>
;
class
DWGraph
:
public
Graph
<
DWVertex
>
{
public:
virtual
void
read
(
std
::
istream
&
stream
)
{
}
virtual
~
DWGraph
()
{}
};
class
DWIR
:
public
virtual
IR
{
public:
...
...
@@ -52,19 +40,34 @@ public:
}
virtual
void
addKernel
(
std
::
shared_ptr
<
Function
>
kernel
)
{
kernels
.
push_back
(
kernel
);
}
virtual
bool
kernelExists
(
const
std
::
string
&
name
)
{
return
false
;
return
std
::
any_of
(
kernels
.
cbegin
(),
kernels
.
cend
(),
[
=
](
std
::
shared_ptr
<
Function
>
i
)
{
return
i
->
getName
()
==
name
;});
}
virtual
std
::
shared_ptr
<
Function
>
getKernel
(
const
std
::
string
&
name
)
{
for
(
auto
f
:
kernels
)
{
if
(
f
->
getName
()
==
name
)
{
return
f
;
}
}
XACCError
(
"Invalid kernel name."
);
}
virtual
std
::
vector
<
std
::
shared_ptr
<
Function
>>
getKernels
()
{
return
kernels
;
}
protected:
/**
* Reference to this QIR's list of quantum functions
*/
std
::
vector
<
std
::
shared_ptr
<
Function
>>
kernels
;
};
}
...
...
quantum/aqc/ir/DWKernel.hpp
View file @
fbdc2091
...
...
@@ -40,6 +40,8 @@ namespace xacc {
namespace
quantum
{
/**
* The DWKernel is an XACC Function that contains
* DWQMI Instructions.
*/
class
DWKernel
:
public
virtual
Function
{
...
...
quantum/aqc/ir/DWQMI.hpp
View file @
fbdc2091
...
...
@@ -39,21 +39,69 @@ namespace xacc {
namespace
quantum
{
/**
* The DWQMI (D=Wave Quantum Machine Instruction) class is an XACC
* Instruction that models a logical problem or hardware bias or
* connection for an optimization problem to be solved on
* the D-Wave QPU. It keeps track of 2 bits indices, if both
* are the same index then this DWQMI Instruction models
* a bias value, and if they are different indices,
* then this Instruction models a logical coupling.
*
* Note that this class can model both problem bias/couplings and
* hardware bias/couplings. The hardware bias/couplings result from
* a minor graph embedding computation.
*
*/
class
DWQMI
:
public
Instruction
{
protected:
/**
* The qubits involved in this Instruction
*/
std
::
vector
<
int
>
qubits
;