Permalink
Browse files

Fix bug of optional args for get_lowest_n() in Davidson algo (#364)

* 1) Fix bug of optional args for get_lowest_n() in Davidson algo; 2) Add unit test for example code of (Parallel)LinearQubitOperator.

* Replace xrange with range.
  • Loading branch information...
sheilaliuxl authored and jarrodmcc committed Jun 12, 2018
1 parent 2637eb6 commit 1e7996d243adfba6fb26905c06ca69a113e61176
@@ -11,11 +11,12 @@
# limitations under the License.
"""This file contains tests of code performance to reveal bottlenecks."""
import numpy
import time
import logging
import numpy
from openfermion.ops import (FermionOperator,
InteractionOperator,
QubitOperator)
from openfermion.transforms import get_fermion_operator, jordan_wigner
from openfermion.utils import (
@@ -44,7 +45,7 @@ def benchmark_molecular_operator_jordan_wigner(n_qubits):
# Convert to a qubit operator.
start = time.time()
qubit_operator = jordan_wigner(molecular_operator)
_ = jordan_wigner(molecular_operator)
end = time.time()
# Return runtime.
@@ -75,7 +76,7 @@ def benchmark_fermion_math_and_normal_order(n_qubits, term_length, power):
numpy.random.randint(2))]
operators_b = [(numpy.random.randint(n_qubits),
numpy.random.randint(2))]
for operator_number in range(term_length):
for _ in range(term_length):
# Make sure the operator is not trivially zero.
operator_a = (numpy.random.randint(n_qubits),
@@ -129,7 +130,7 @@ def benchmark_jordan_wigner_sparse(n_qubits):
# Map to SparseOperator class.
start_time = time.time()
sparse_operator = jordan_wigner_sparse(fermion_operator)
_ = jordan_wigner_sparse(fermion_operator)
runtime = time.time() - start_time
return runtime
@@ -148,20 +149,20 @@ def benchmark_linear_qubit_operator(n_qubits, n_terms, processes=None):
runtime_matvec: The time it takes to perform matrix multiplication.
"""
# Generates Qubit Operator with specified number of terms.
m = {
map_int_to_operator = {
0: 'X',
1: 'Y',
2: 'Z',
}
qubit_operator = QubitOperator.zero()
for _ in xrange(n_terms):
for _ in range(n_terms):
tuples = []
for i in xrange(n_qubits):
op = numpy.random.randint(4)
for i in range(n_qubits):
operator = numpy.random.randint(4)
# 3 is 'I', so just skip.
if op > 2:
if operator > 2:
continue
tuples.append((i, m[op]))
tuples.append((i, map_int_to_operator[operator]))
if tuples:
qubit_operator += QubitOperator(tuples, 1.00)
@@ -180,59 +181,63 @@ def benchmark_linear_qubit_operator(n_qubits, n_terms, processes=None):
vec = numpy.random.rand(2 ** n_qubits)
# Performs matrix multiplication.
start = time.time()
matvec = linear_operator * vec
_ = linear_operator * vec
end = time.time()
runtime_matvec = end - start
return runtime_operator, runtime_matvec
# Sets up each benchmark run.
def run_molecular_operator_jordan_wigner():
def run_molecular_operator_jordan_wigner(n_qubits=18):
"""Run InteractionOperator.jordan_wigner_transform() benchmark."""
n_qubits = 18
print('Starting test on InteractionOperator.jordan_wigner_transform()')
logging.info('Starting test on '
'InteractionOperator.jordan_wigner_transform()')
logging.info('n_qubits = %d.', n_qubits)
runtime = benchmark_molecular_operator_jordan_wigner(n_qubits)
print('InteractionOperator.jordan_wigner_transform() ' +
'takes {} seconds on {} qubits.\n'.format(runtime, n_qubits))
logging.info('InteractionOperator.jordan_wigner_transform() takes %f '
'seconds.\n', runtime)
return runtime
def run_fermion_math_and_normal_order():
def run_fermion_math_and_normal_order(n_qubits=20, term_length=10, power=15):
"""Run benchmark on FermionOperator math and normal-ordering."""
n_qubits = 20
term_length = 10
power = 15
print('Starting test on FermionOperator math and normal ordering.')
logging.info('Starting test on FermionOperator math and normal ordering.')
logging.info('(n_qubits, term_length, power) = (%d, %d, %d).', n_qubits,
term_length, power)
runtime_math, runtime_normal = benchmark_fermion_math_and_normal_order(
n_qubits, term_length, power)
print('Math took {} seconds. Normal ordering took {} seconds.\n'.format(
runtime_math, runtime_normal))
logging.info('Math took %f seconds. Normal ordering took %f seconds.\n',
runtime_math, runtime_normal)
return runtime_math, runtime_normal
def run_jordan_wigner_sparse():
def run_jordan_wigner_sparse(n_qubits=10):
"""Run FermionOperator.jordan_wigner_sparse() benchmark."""
n_qubits = 10
print('Starting test on FermionOperator.jordan_wigner_sparse().')
logging.info('Starting test on FermionOperator.jordan_wigner_sparse().')
logging.info('n_qubits = %d.', n_qubits)
runtime = benchmark_jordan_wigner_sparse(n_qubits)
print('Construction of SparseOperator took {} seconds.\n'.format(
runtime))
logging.info('Construction of SparseOperator took %f seconds.\n', runtime)
return runtime
def run_linear_qubit_operator():
def run_linear_qubit_operator(n_qubits=16, n_terms=10, processes=10):
"""Run linear_qubit_operator benchmark."""
n_qubits = 20
n_terms = 10
processes = 10
print('Starting test on linear_qubit_operator().')
logging.info('Starting test on linear_qubit_operator().')
logging.info('(n_qubits, n_terms) = (%d, %d).', n_qubits, n_terms)
_, runtime_sequential = benchmark_linear_qubit_operator(n_qubits, n_terms)
_, runtime_parallel = benchmark_linear_qubit_operator(n_qubits, n_terms,
processes)
print('LinearQubitOperator took {} seconds, while '
'ParallelQubitOperator took {} seconds with '
'(n_qubits, n_terms, processes) = ({}, {}, {})\n'.format(
runtime_sequential, runtime_parallel,
n_qubits, n_terms, processes))
logging.info('LinearQubitOperator took %f seconds, while '
'ParallelQubitOperator took %f seconds with %d processes, and '
'ratio is %.2f.\n', runtime_sequential, runtime_parallel,
processes, runtime_sequential / runtime_parallel)
return runtime_sequential, runtime_parallel
# Run benchmarks.
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
# Seed random number generator.
numpy.random.seed(8)
@@ -11,18 +11,21 @@
# limitations under the License.
"""Tests the code in the examples directory of the git repo."""
import nbformat
import numpy
import os
import subprocess
import sys
import tempfile
import unittest
import nbformat
import numpy
from openfermion.config import THIS_DIRECTORY
class ExampleTest(unittest.TestCase):
"""Unit tests for example scripts."""
def setUp(self):
string_length = len(THIS_DIRECTORY)
@@ -32,6 +35,7 @@ def setUp(self):
self.jw_bk_demo = 'jordan_wigner_and_bravyi_kitaev_transforms.ipynb'
def test_demo(self):
"""Unit test for demo."""
# Determine if python 2 or 3 is being used.
major_version, minor_version = sys.version_info[:2]
if major_version == 2 or minor_version == 6:
@@ -52,17 +56,18 @@ def test_demo(self):
self.directory + self.demo_name]
subprocess.check_call(args)
output_file.seek(0)
nb = nbformat.read(output_file, nbformat.current_nbformat)
nb_data = nbformat.read(output_file, nbformat.current_nbformat)
# Parse output and make sure there are no errors.
errors = [output for cell in nb.cells if "outputs" in cell for
errors = [output for cell in nb_data.cells if "outputs" in cell for
output in cell["outputs"] if
output.output_type == "error"]
else:
errors = []
self.assertEqual(errors, [])
def test_binary_code_transforms_demo(self):
"""Unit test for demo."""
# Determine if python 2 or 3 is being used.
major_version, minor_version = sys.version_info[:2]
if major_version == 2 or minor_version == 6:
@@ -83,17 +88,18 @@ def test_binary_code_transforms_demo(self):
self.directory + self.binary_code_transforms_demo]
subprocess.check_call(args)
output_file.seek(0)
nb = nbformat.read(output_file, nbformat.current_nbformat)
nb_data = nbformat.read(output_file, nbformat.current_nbformat)
# Parse output and make sure there are no errors.
errors = [output for cell in nb.cells if "outputs" in cell for
errors = [output for cell in nb_data.cells if "outputs" in cell for
output in cell["outputs"] if
output.output_type == "error"]
else:
errors = []
self.assertEqual(errors, [])
def test_jordan_wigner_and_bravyi_kitaev_transforms_demo(self):
"""Unit test for demo."""
# Determine if python 2 or 3 is being used.
major_version, minor_version = sys.version_info[:2]
if major_version == 2 or minor_version == 6:
@@ -114,41 +120,47 @@ def test_jordan_wigner_and_bravyi_kitaev_transforms_demo(self):
self.directory + self.jw_bk_demo]
subprocess.check_call(args)
output_file.seek(0)
nb = nbformat.read(output_file, nbformat.current_nbformat)
nb_data = nbformat.read(output_file, nbformat.current_nbformat)
# Parse output and make sure there are no errors.
errors = [output for cell in nb.cells if "outputs" in cell for
errors = [output for cell in nb_data.cells if "outputs" in cell for
output in cell["outputs"] if
output.output_type == "error"]
else:
errors = []
self.assertEqual(errors, [])
def test_performance_benchmarks(self):
"""Unit test for examples/performance_benchmark.py."""
# Import performance benchmarks and seed random number generator.
sys.path.append(self.directory)
from performance_benchmarks import (
benchmark_fermion_math_and_normal_order,
benchmark_jordan_wigner_sparse,
benchmark_molecular_operator_jordan_wigner)
run_fermion_math_and_normal_order,
run_jordan_wigner_sparse,
run_molecular_operator_jordan_wigner,
run_linear_qubit_operator,
)
numpy.random.seed(1)
runtime_upper_bound = 600
# Run InteractionOperator.jordan_wigner_transform() benchmark.
n_qubits = 10
runtime = benchmark_molecular_operator_jordan_wigner(n_qubits)
self.assertLess(runtime, 600)
runtime = run_molecular_operator_jordan_wigner(n_qubits=10)
self.assertLess(runtime, runtime_upper_bound)
# Run benchmark on FermionOperator math and normal-ordering.
n_qubits = 10
term_length = 5
power = 5
runtime_math, runtime_normal = benchmark_fermion_math_and_normal_order(
n_qubits, term_length, power)
self.assertLess(runtime_math, 600)
self.assertLess(runtime_normal, 600)
runtime_math, runtime_normal = run_fermion_math_and_normal_order(
n_qubits=10, term_length=5, power=5)
self.assertLess(runtime_math, runtime_upper_bound)
self.assertLess(runtime_normal, runtime_upper_bound)
# Run FermionOperator.jordan_wigner_sparse() benchmark.
n_qubits = 10
runtime = benchmark_jordan_wigner_sparse(n_qubits)
runtime = run_jordan_wigner_sparse(n_qubits=10)
self.assertLess(runtime, 600)
# Run (Parallel)LinearQubitOperator benchmark.
runtime_sequential, runtime_parallel = run_linear_qubit_operator(
n_qubits=10, n_terms=10, processes=10)
self.assertLess(runtime_sequential, runtime_upper_bound)
self.assertLess(runtime_parallel, runtime_upper_bound)
@@ -122,6 +122,10 @@ def get_lowest_n(self, n_lowest=1, initial_guess=None, max_iterations=None):
# 2. Checks for initial guess vectors' dimension is the same to that of
# the operator.
if initial_guess is None:
initial_guess = generate_random_vectors(
len(self.linear_operator_diagonal), n_lowest,
real_only=self.options.real_only)
if initial_guess.shape[0] != len(self.linear_operator_diagonal):
raise ValueError('Guess vectors have a different dimension with '
'linear opearator diagonal elements: {} != {}.'
@@ -186,6 +186,14 @@ def test_get_lowest_fail(self):
self.assertTrue(numpy.allclose(eigen_values,
numpy.array([1.41556103])))
def test_get_lowest_with_default(self):
"""Test for get_lowest_n() with default n_lowest = 1."""
numpy.random.seed(len(self.eigen_values))
success, eigen_values, _ = self.davidson.get_lowest_n()
self.assertTrue(success)
self.assertTrue(numpy.allclose(eigen_values, self.eigen_values[:1]))
def test_get_lowest_one(self):
"""Test for get_lowest_n() with n_lowest = 1."""
n_lowest = 1

0 comments on commit 1e7996d

Please sign in to comment.