Skip to content

Commit 6a31e57

Browse files
authored
ProjectQ v0.3.1
2 parents d5ccfe1 + 5a68930 commit 6a31e57

23 files changed

+525
-96
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ matrix:
3030
sources: ['ubuntu-toolchain-r-test']
3131
packages: ['gcc-4.9', 'g++-4.9']
3232
env: CC=gcc-4.9 CXX=g++-4.9 PYTHON=3.5
33+
- os: linux
34+
python: "3.6"
35+
addons:
36+
apt:
37+
sources: ['ubuntu-toolchain-r-test']
38+
packages: ['gcc-4.9', 'g++-4.9']
39+
env: CC=gcc-4.9 CXX=g++-4.9 PYTHON=3.6
3340

3441
install:
3542
- if [ "${PYTHON:0:1}" = "3" ]; then export PY=3; fi

README.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ ProjectQ - An open source software framework for quantum computing
77
.. image:: https://coveralls.io/repos/github/ProjectQ-Framework/ProjectQ/badge.svg
88
:target: https://coveralls.io/github/ProjectQ-Framework/ProjectQ
99

10+
.. image:: https://readthedocs.org/projects/projectq/badge/?version=latest
11+
:target: http://projectq.readthedocs.io/en/latest/?badge=latest
12+
:alt: Documentation Status
1013

1114
ProjectQ is an open source effort for quantum computing.
1215

@@ -26,8 +29,8 @@ This allows users to
2629
Getting started
2730
---------------
2831

29-
To start using ProjectQ, simply follow the installation instructions in the `tutorials <http://projectq.ch/docs/tutorials.html>`__. There, you will also find OS-specific hints, a small introduction to the ProjectQ syntax, and a few `code examples <http://projectq.ch/docs/examples.html>`__. Also, make sure to check out the `ProjectQ
30-
website <http://www.projectq.ch>`__ and the detailed `code documentation <http://projectq.ch/docs/>`__.
32+
To start using ProjectQ, simply follow the installation instructions in the `tutorials <http://projectq.readthedocs.io/en/latest/tutorials.html>`__. There, you will also find OS-specific hints, a small introduction to the ProjectQ syntax, and a few `code examples <http://projectq.readthedocs.io/en/latest/examples.html>`__. Also, make sure to check out the `ProjectQ
33+
website <http://www.projectq.ch>`__ and the detailed `code documentation <http://projectq.readthedocs.io/en/latest/>`__.
3134

3235
How to contribute
3336
-----------------

docs/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
# add these directories to sys.path here. If the directory is relative to the
1818
# documentation root, use os.path.abspath to make it absolute, like shown here.
1919
#
20-
# import os
21-
# import sys
22-
# sys.path.insert(0, os.path.abspath('.'))
20+
import os
21+
import sys
22+
sys.path.insert(0, os.path.abspath('..'))
2323

2424
# -- General configuration ------------------------------------------------
2525

docs/tutorials.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ or, alternatively, `clone/download <https://github.com/projectq-framework>`_ thi
4040
4141
Please note that the compiler you specify must support **C++11**!
4242

43+
.. note::
44+
Please use pip version v6.1.0 or higher as this ensures that dependencies are installed in the `correct order <https://pip.pypa.io/en/stable/reference/pip_install/#installation-order>`_.
45+
4346

4447
Detailed instructions and OS-specific hints
4548
-------------------------------------------

projectq/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
# limitations under the License.
1212

1313
"""Define version number here and read it from setup.py automatically"""
14-
__version__ = "0.3.0"
14+
__version__ = "0.3.1"

projectq/backends/_sim/_cppkernels/simulator.hpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class Simulator{
6464
}
6565

6666
bool get_classical_value(unsigned id, calc_type tol = 1.e-12){
67+
run();
6768
unsigned pos = map_[id];
6869
std::size_t delta = (1UL << pos);
6970

@@ -264,6 +265,40 @@ class Simulator{
264265
return expectation;
265266
}
266267

268+
calc_type get_probability(std::vector<bool> const& bit_string,
269+
std::vector<unsigned> const& ids){
270+
run();
271+
if (!check_ids(ids))
272+
throw(std::runtime_error("get_probability(): Unknown qubit id. Please make sure you have called eng.flush()."));
273+
std::size_t mask = 0, bit_str = 0;
274+
for (unsigned i = 0; i < ids.size(); ++i){
275+
mask |= 1UL << map_[ids[i]];
276+
bit_str |= (bit_string[i]?1UL:0UL) << map_[ids[i]];
277+
}
278+
calc_type probability = 0.;
279+
#pragma omp parallel for reduction(+:probability) schedule(static)
280+
for (std::size_t i = 0; i < vec_.size(); ++i)
281+
if ((i & mask) == bit_str)
282+
probability += std::norm(vec_[i]);
283+
return probability;
284+
}
285+
286+
complex_type const& get_amplitude(std::vector<bool> const& bit_string,
287+
std::vector<unsigned> const& ids){
288+
run();
289+
std::size_t chk = 0;
290+
std::size_t index = 0;
291+
for (unsigned i = 0; i < ids.size(); ++i){
292+
if (map_.count(ids[i]) == 0)
293+
break;
294+
chk |= 1UL << map_[ids[i]];
295+
index |= (bit_string[i]?1UL:0UL) << map_[ids[i]];
296+
}
297+
if (chk + 1 != vec_.size())
298+
throw(std::runtime_error("The second argument to get_amplitude() must be a permutation of all allocated qubits. Please make sure you have called eng.flush()."));
299+
return vec_[index];
300+
}
301+
267302
void emulate_time_evolution(TermsDict const& tdict, calc_type const& time,
268303
std::vector<unsigned> const& ids,
269304
std::vector<unsigned> const& ctrl){
@@ -314,6 +349,22 @@ class Simulator{
314349
}
315350
}
316351

352+
void set_wavefunction(StateVector const& wavefunction, std::vector<unsigned> const& ordering){
353+
run();
354+
// make sure there are 2^n amplitudes for n qubits
355+
assert(wavefunction.size() == (1UL << ordering.size()));
356+
// check that all qubits have been allocated previously
357+
if (map_.size() != ordering.size() || !check_ids(ordering))
358+
throw(std::runtime_error("set_wavefunction(): Invalid mapping provided. Please make sure all qubits have been allocated previously (call eng.flush())."));
359+
360+
// set mapping and wavefunction
361+
for (unsigned i = 0; i < ordering.size(); ++i)
362+
map_[ordering[i]] = i;
363+
#pragma omp parallel for schedule(static)
364+
for (std::size_t i = 0; i < wavefunction.size(); ++i)
365+
vec_[i] = wavefunction[i];
366+
}
367+
317368
void run(){
318369
if (fused_gates_.size() < 1)
319370
return;
@@ -383,6 +434,13 @@ class Simulator{
383434
return ctrlmask;
384435
}
385436

437+
bool check_ids(std::vector<unsigned> const& ids){
438+
for (auto id : ids)
439+
if (!map_.count(id))
440+
return false;
441+
return true;
442+
}
443+
386444
unsigned N_; // #qubits
387445
StateVector vec_;
388446
Map map_;

projectq/backends/_sim/_cppsim.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ PYBIND11_PLUGIN(_cppsim) {
5252
.def("emulate_math", &emulate_math_wrapper<QuRegs>)
5353
.def("get_expectation_value", &Simulator::get_expectation_value)
5454
.def("emulate_time_evolution", &Simulator::emulate_time_evolution)
55+
.def("get_probability", &Simulator::get_probability)
56+
.def("get_amplitude", &Simulator::get_amplitude)
57+
.def("set_wavefunction", &Simulator::set_wavefunction)
5558
.def("run", &Simulator::run)
5659
.def("cheat", &Simulator::cheat)
5760
;

projectq/backends/_sim/_pysim.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,65 @@ def get_expectation_value(self, terms_dict, ids):
248248
self._state = _np.copy(current_state)
249249
return expectation
250250

251+
def get_probability(self, bit_string, ids):
252+
"""
253+
Return the probability of the outcome `bit_string` when measuring
254+
the qubits given by the list of ids.
255+
256+
Args:
257+
bit_string (list[bool|int]): Measurement outcome.
258+
ids (list[int]): List of qubit ids determining the ordering.
259+
260+
Returns:
261+
Probability of measuring the provided bit string.
262+
263+
Raises:
264+
RuntimeError if an unknown qubit id was provided.
265+
"""
266+
for i in range(len(ids)):
267+
if ids[i] not in self._map:
268+
raise RuntimeError("get_probability(): Unknown qubit id. "
269+
"Please make sure you have called "
270+
"eng.flush().")
271+
mask = 0
272+
bit_str = 0
273+
for i in range(len(ids)):
274+
mask |= (1 << self._map[ids[i]])
275+
bit_str |= (bit_string[i] << self._map[ids[i]])
276+
probability = 0.
277+
for i in range(len(self._state)):
278+
if (i & mask) == bit_str:
279+
e = self._state[i]
280+
probability += e.real**2 + e.imag**2
281+
return probability
282+
283+
def get_amplitude(self, bit_string, ids):
284+
"""
285+
Return the probability amplitude of the supplied `bit_string`.
286+
The ordering is given by the list of qubit ids.
287+
288+
Args:
289+
bit_string (list[bool|int]): Computational basis state
290+
ids (list[int]): List of qubit ids determining the
291+
ordering. Must contain all allocated qubits.
292+
293+
Returns:
294+
Probability amplitude of the provided bit string.
295+
296+
Raises:
297+
RuntimeError if the second argument is not a permutation of all
298+
allocated qubits.
299+
"""
300+
if not set(ids) == set(self._map):
301+
raise RuntimeError("The second argument to get_amplitude() must"
302+
" be a permutation of all allocated qubits. "
303+
"Please make sure you have called "
304+
"eng.flush().")
305+
index = 0
306+
for i in range(len(ids)):
307+
index |= (bit_string[i] << self._map[ids[i]])
308+
return self._state[index]
309+
251310
def emulate_time_evolution(self, terms_dict, time, ids, ctrlids):
252311
"""
253312
Applies exp(-i*time*H) to the wave function, i.e., evolves under
@@ -325,6 +384,28 @@ def kernel(u, d, m):
325384
self._state[id2],
326385
m)
327386

387+
def set_wavefunction(self, wavefunction, ordering):
388+
"""
389+
Set wavefunction and qubit ordering.
390+
391+
Args:
392+
wavefunction (list[complex]): Array of complex amplitudes
393+
describing the wavefunction (must be normalized).
394+
ordering (list): List of ids describing the new ordering of qubits
395+
(i.e., the ordering of the provided wavefunction).
396+
"""
397+
# wavefunction contains 2^n values for n qubits
398+
assert len(wavefunction) == (1 << len(ordering))
399+
# all qubits must have been allocated before
400+
if (not all([Id in self._map for Id in ordering])
401+
or len(self._map) != len(ordering)):
402+
raise RuntimeError("set_wavefunction(): Invalid mapping provided."
403+
" Please make sure all qubits have been "
404+
"allocated previously (call eng.flush()).")
405+
406+
self._state = _np.array(wavefunction)
407+
self._map = {ordering[i]: i for i in range(len(ordering))}
408+
328409
def run(self):
329410
"""
330411
Dummy function to implement the same interface as the c++ simulator.

projectq/backends/_sim/_simulator.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,82 @@ def get_expectation_value(self, qubit_operator, qureg):
120120
121121
Returns:
122122
Expectation value
123+
124+
Note:
125+
Make sure all previous commands (especially allocations) have
126+
passed through the compilation chain (call main_engine.flush() to
127+
make sure).
123128
"""
124129
operator = [(list(term), coeff) for (term, coeff)
125130
in qubit_operator.terms.items()]
126131
return self._simulator.get_expectation_value(operator,
127132
[qb.id for qb in qureg])
128133

134+
def get_probability(self, bit_string, qureg):
135+
"""
136+
Return the probability of the outcome `bit_string` when measuring
137+
the quantum register `qureg`.
138+
139+
Args:
140+
bit_string (list[bool|int]|string[0|1]): Measurement outcome.
141+
qureg (Qureg|list[Qubit]): Quantum register.
142+
143+
Returns:
144+
Probability of measuring the provided bit string.
145+
146+
Note:
147+
Make sure all previous commands (especially allocations) have
148+
passed through the compilation chain (call main_engine.flush() to
149+
make sure).
150+
"""
151+
bit_string = [bool(int(b)) for b in bit_string]
152+
return self._simulator.get_probability(bit_string,
153+
[qb.id for qb in qureg])
154+
155+
def get_amplitude(self, bit_string, qureg):
156+
"""
157+
Return the probability amplitude of the supplied `bit_string`.
158+
The ordering is given by the quantum register `qureg`, which must
159+
contain all allocated qubits.
160+
161+
Args:
162+
bit_string (list[bool|int]|string[0|1]): Computational basis state
163+
qureg (Qureg|list[Qubit]): Quantum register determining the
164+
ordering. Must contain all allocated qubits.
165+
166+
Returns:
167+
Probability amplitude of the provided bit string.
168+
169+
Note:
170+
Make sure all previous commands (especially allocations) have
171+
passed through the compilation chain (call main_engine.flush() to
172+
make sure).
173+
"""
174+
bit_string = [bool(int(b)) for b in bit_string]
175+
return self._simulator.get_amplitude(bit_string,
176+
[qb.id for qb in qureg])
177+
178+
def set_wavefunction(self, wavefunction, qureg):
179+
"""
180+
Set the wavefunction and the qubit ordering of the simulator.
181+
182+
The simulator will adopt the ordering of qureg (instead of reordering
183+
the wavefunction).
184+
185+
Args:
186+
wavefunction (list[complex]): Array of complex amplitudes
187+
describing the wavefunction (must be normalized).
188+
qureg (Qureg|list[Qubit]): Quantum register determining the
189+
ordering. Must contain all allocated qubits.
190+
191+
Note:
192+
Make sure all previous commands (especially allocations) have
193+
passed through the compilation chain (call main_engine.flush() to
194+
make sure).
195+
"""
196+
self._simulator.set_wavefunction(wavefunction,
197+
[qb.id for qb in qureg])
198+
129199
def cheat(self):
130200
"""
131201
Access the ordering of the qubits and the state vector directly.
@@ -137,6 +207,10 @@ def cheat(self):
137207
A tuple where the first entry is a dictionary mapping qubit
138208
indices to bit-locations and the second entry is the corresponding
139209
state vector.
210+
211+
Note:
212+
Make sure all previous commands have passed through the
213+
compilation chain (call main_engine.flush() to make sure).
140214
"""
141215
return self._simulator.cheat()
142216

0 commit comments

Comments
 (0)