Skip to content

Commit

Permalink
Release/1.3 (#189)
Browse files Browse the repository at this point in the history
- optimize polynomial data structure in the compilation
- optimize the construction of sum expressions
- optimize the to_qubo method to run faster
- fix hash collision to avoid a crash in robin_hood
  • Loading branch information
kotarotanahashi authored Oct 3, 2022
1 parent 4e5c543 commit aafc0df
Show file tree
Hide file tree
Showing 29 changed files with 1,389 additions and 1,357 deletions.
649 changes: 0 additions & 649 deletions .circleci/config.yml

This file was deleted.

3 changes: 1 addition & 2 deletions .github/workflows/build_and_upolad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ jobs:
path: dist
- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_PASSWORD }}

upload_test_pypi:
Expand All @@ -185,7 +184,7 @@ jobs:
path: dist
- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_TEST_PASSWORD }}
repository_url: https://test.pypi.org/legacy/
skip_existing: true
verbose: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ __pycache__/
# Distribution / packaging
.Python
build/
build_test/
develop-eggs/
dist/
downloads/
Expand Down
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ include(external/eigen.cmake)
include(external/pybind11.cmake)
include(external/robin_hood.cmake)

pybind11_add_module(cpp_pyqubo src/main.cpp)
if(DEFINED ENV{build_test})
add_executable(cpp_pyqubo src/test.cpp)
else()
pybind11_add_module(cpp_pyqubo src/main.cpp)
endif()

target_compile_definitions(cpp_pyqubo PRIVATE VERSION_INFO=${PYQUBO_VERSION_INFO})
target_compile_features(cpp_pyqubo PRIVATE cxx_std_17)
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ By calling ``model.to_qubo()``, we get the resulting QUBO.
>>> H = (4*s1 + 2*s2 + 7*s3 + s4)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo()
>>> pprint(qubo)
>>> pprint(qubo) # doctest: +SKIP
{('s1', 's1'): -160.0,
('s1', 's2'): 64.0,
('s1', 's3'): 224.0,
Expand Down
127 changes: 127 additions & 0 deletions benchmark/benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from pyqubo import Array, Constraint, Placeholder
import logging
import time
import argparse
import numpy as np
from timeout_decorator import timeout, TimeoutError
from memory_profiler import memory_usage


parser = argparse.ArgumentParser()

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("benchmark_tsp")


def number_partition_with_timeout(n, timeout_sec):

@timeout(timeout_sec)
def number_partition(n):
t0 = time.time()
s = Array.create('s', n, 'SPIN')
numbers = np.random.randint(0, 10, n)
H = sum([si * ni for si, ni in zip(s, numbers)])**2

# Compile model
t1 = time.time()
model = H.compile()
t2 = time.time()
qubo, offset = model.to_qubo(index_label=False)
t3 = time.time()
print("len(qubo)", len(qubo))

return t1-t0, t2-t1, t3-t2

return number_partition(n)

def tsp_with_timeout(n_city, timeout_sec):

@timeout(timeout_sec)
def tsp(n_city):
t0 = time.time()
x = Array.create('c', (n_city, n_city), 'BINARY')
use_for_loop=False

# Constraint not to visit more than two cities at the same time.
time_const = 0.0
for i in range(n_city):
# If you wrap the hamiltonian by Const(...), this part is recognized as constraint
time_const += Constraint((sum(x[i, j] for j in range(n_city)) - 1)**2, label="time{}".format(i))

# Constraint not to visit the same city more than twice.
city_const = 0.0
for j in range(n_city):
city_const += Constraint((sum(x[i, j] for i in range(n_city)) - 1)**2, label="city{}".format(j))

# distance of route
feed_dict = {}

if use_for_loop:
distance = 0.0
for i in range(n_city):
for j in range(n_city):
for k in range(n_city):
# we set the constant distance
d_ij = 10
distance += d_ij * x[k, i] * x[(k + 1) % n_city, j]

else:
distance = []
for i in range(n_city):
for j in range(n_city):
for k in range(n_city):
# we set the constant distance
d_ij = 10
distance.append(d_ij * x[k, i] * x[(k + 1) % n_city, j])
distance = sum(distance)

print("express done")

# Construct hamiltonian
A = Placeholder("A")
H = distance

feed_dict["A"] = 1.0

# Compile model
t1 = time.time()
model = H.compile()
t2 = time.time()
qubo, offset = model.to_qubo(index_label=False, feed_dict=feed_dict)
t3 = time.time()

print("len(qubo)", len(qubo))

return t1-t0, t2-t1, t3-t2

return tsp(n_city)



def measure(problem, step, init_size, max_size, timeout):
if problem == "tsp":
f = tsp_with_timeout
elif problem == "number_partition":
f = number_partition_with_timeout

for n in range(init_size, max_size+step, step):
try:
max_memory, (express_time, compile_time, to_qubo_time) = memory_usage((f, (n, timeout)), max_usage=True, retval=True)
logger.info("Memory usage is {} MB for n={}".format(max_memory, n))
logger.info("Elapsed time is {} sec (expression: {} sec, compile: {} sec, to_qubo {} sec), for n={}".format(
express_time+compile_time+to_qubo_time, express_time, compile_time, to_qubo_time, n))

except TimeoutError as e:
logger.error("TimeoutError: Elapsed time exceeded {} sec for n_city={}".format(timeout, n))
break


if __name__=="__main__":
parser.add_argument('-p', '--problem', type=str)
parser.add_argument('-m', '--max_size', type=int)
parser.add_argument('-i', '--init_size', type=int)
parser.add_argument('-s', '--step', type=int)
parser.add_argument('-t', '--timeout', type=int)
args = parser.parse_args()
#number_partition_with_timeout(2000, timeout_sec=10)
measure(args.problem, args.step, args.init_size, args.max_size, args.timeout)
75 changes: 0 additions & 75 deletions benchmark/benchmark_tsp.py

This file was deleted.

6 changes: 3 additions & 3 deletions docs/reference/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Model
>>> model.to_qubo(index_label=True) # doctest: +SKIP
({(2, 2): 3.0, (1, 1): 2.0, (0, 0): 1.0}, 0.0)
>>> model.variables
['a', 'b', 'c']
['c', 'a', 'b']

This indicaretes the mapping of indices and labels as 'c'->0, 'a'->1, 'b'->2

Expand Down Expand Up @@ -96,7 +96,7 @@ Model
>>> pprint(model.to_qubo(index_label=True)) # doctest: +SKIP
({(0, 0): 3.0, (0, 2): 1.0, (1, 1): 0.0, (1, 2): 1.0, (2, 2): 0.0}, 0.0)
>>> model.variables
['x', 'y', 'z']
['z', 'x', 'y']


.. py:method:: to_ising(index_label=False, feed_dict=None)
Expand Down Expand Up @@ -129,7 +129,7 @@ Model
>>> pprint(model.to_ising(index_label=True)) # doctest: +SKIP
({0: 1.75, 1: 0.25, 2: 0.5}, {(0, 2): 0.25, (1, 2): 0.25}, 2.0)
>>> model.variables
['x', 'y', 'z']
['z', 'x', 'y']


.. py:method:: to_bqm(index_label=False, feed_dict=None)
Expand Down
2 changes: 1 addition & 1 deletion external/robin_hood.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
robin_hood
GIT_REPOSITORY https://github.com/martinus/robin-hood-hashing
GIT_TAG 3.11.2
GIT_TAG 3.11.3
)

FetchContent_GetProperties(robin_hood)
Expand Down
2 changes: 1 addition & 1 deletion pyqubo/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Array:
>>> array[:, 1] # = array[(slice(None), 1)]
Array([Binary('x1'), Binary('x3')])
>>> sum(array[:, 1])
>>> sum(array[:, 1]) # doctest: +SKIP
(Binary('x1') + Binary('x3'))
Use list or tuple to select a subset of the array.
Expand Down
2 changes: 2 additions & 0 deletions pyqubo/integer/one_hot_enc_integer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ def __init__(self, label, value_range, strength):
express = SubH(lower + sum(i*x for i, x in enumerate(self.array)), label=label)
penalty = self.constraint * strength

self._express = express

super().__init__(
label=label,
value_range=value_range,
Expand Down
4 changes: 2 additions & 2 deletions pyqubo/package_info.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# (major, minor, patch, prerelease)

VERSION = (1, 2, 0, "")
VERSION = (1, 3, 0, "")
__shortversion__ = '.'.join(map(str, VERSION[:3]))
__version__ = '.'.join(map(str, VERSION[:3])) + "".join(VERSION[3:])

__package_name__ = 'pyqubo'
__contact_names__ = 'Recruit Communications Co., Ltd.'
__contact_names__ = 'Recruit Co., Ltd.'
__contact_emails__ = 'rco_pyqubo@ml.cocorou.jp'
__homepage__ = 'https://pyqubo.readthedocs.io/en/latest/'
__repository_url__ = 'https://github.com/recruit-communications/pyqubo'
Expand Down
Loading

0 comments on commit aafc0df

Please sign in to comment.