Skip to content

Commit 7e47114

Browse files
committed
Experiment with using taskflow for parallel presolving
1 parent ad18c37 commit 7e47114

11 files changed

Lines changed: 75 additions & 8 deletions

File tree

.circleci/config.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ jobs:
2222

2323
steps:
2424
- checkout
25+
- run: git submodule sync
26+
- run: git submodule update --init
2527
- setup_remote_docker
2628
- restore_cache: &build-linux-restore-cache
2729
keys:
@@ -61,6 +63,8 @@ jobs:
6163

6264
steps: &build-steps
6365
- checkout
66+
- run: git submodule sync
67+
- run: git submodule update --init
6468
- restore_cache: *build-linux-restore-cache
6569
- run: *build-linux-wheels
6670
- save_cache: *build-linux-save-cache
@@ -90,6 +94,8 @@ jobs:
9094

9195
steps:
9296
- checkout
97+
- run: git submodule sync
98+
- run: git submodule update --init
9399
- run:
94100
name: build sdist
95101
command: |
@@ -115,6 +121,8 @@ jobs:
115121

116122
steps:
117123
- checkout
124+
- run: git submodule sync
125+
- run: git submodule update --init
118126
- run:
119127
name: build wheels
120128
command: |
@@ -152,6 +160,8 @@ jobs:
152160

153161
steps:
154162
- checkout
163+
- run: git submodule sync
164+
- run: git submodule update --init
155165
- run:
156166
name: install dependencies
157167
command: |
@@ -181,6 +191,8 @@ jobs:
181191

182192
steps:
183193
- checkout
194+
- run: git submodule sync
195+
- run: git submodule update --init
184196
- run:
185197
name: install doxygen
186198
command: sudo apt-get install doxygen

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
path = testscpp/Catch2
33
url = https://github.com/catchorg/Catch2.git
44
branch = v2.x
5+
[submodule "extern/taskflow"]
6+
path = extern/taskflow
7+
url = git@github.com:taskflow/taskflow.git

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
include pyproject.toml
22
recursive-include dwave/preprocessing/include/ *.hpp *.h
33
recursive-include dwave/preprocessing *.pyx *.pxd *.pyx.src
4+
graft extern/taskflow/taskflow
5+
include extern/taskflow/LICENSE

dwave/preprocessing/include/dwave/presolve.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@
1414

1515
#pragma once
1616

17+
#include <chrono>
18+
#include <thread>
19+
20+
1721
#include <algorithm>
1822
#include <unordered_map>
1923
#include <utility>
2024
#include <vector>
2125

22-
#include "dimod/constrained_quadratic_model.h"
26+
#include <dimod/constrained_quadratic_model.h>
27+
#include <taskflow/taskflow.hpp>
2328

2429
namespace dwave {
2530
namespace presolve {
@@ -134,10 +139,24 @@ class Presolver {
134139
/// Apply any loaded presolve techniques. Acts of the model() in-place.
135140
void apply();
136141

142+
void apply_parallel() {
143+
tf::Executor executor;
144+
tf::Taskflow taskflow;
145+
146+
taskflow.for_each_index(0, static_cast<int>(model_.num_constraints()), 1,
147+
[&](int i) { do_slow_thing(i); });
148+
149+
executor.run(taskflow).wait();
150+
}
151+
137152
/// Detach the constrained quadratic model and return it.
138153
/// This clears the model from the presolver.
139154
model_type detach_model();
140155

156+
void do_slow_thing(index_type c) {
157+
std::this_thread::sleep_for(std::chrono::seconds(1));
158+
}
159+
141160
/// Load the default presolve techniques.
142161
void load_default_presolvers();
143162

dwave/preprocessing/libcpp.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ cdef extern from "dwave/presolve.h" namespace "dwave::presolve" nogil:
2929
Presolver()
3030
Presolver(model_type)
3131
void apply() except+
32+
void apply_parallel() except+
3233
model_type detach_model()
3334
void load_default_presolvers()
3435
model_type& model()

dwave/preprocessing/presolve/cypresolve.pyx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ cdef class cyPresolver:
4747
self.cpppresolver.apply()
4848
self._model_num_variables = self.cpppresolver.model().num_variables()
4949

50+
def apply_parallel(self):
51+
import time
52+
53+
t = time.perf_counter()
54+
self.cpppresolver.apply_parallel()
55+
return time.perf_counter() - t
56+
5057
def clear_model(self):
5158
"""Clear the held model. This is useful to save memory."""
5259
self.cpppresolver.detach_model()

extern/taskflow

Submodule taskflow added at f1490ff

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
from distutils.command.build_ext import build_ext as _build_ext
2424

2525
extra_compile_args = {
26-
'msvc': ['/EHsc'],
27-
'unix': ['-std=c++11'],
26+
'msvc': ['/std:c++17', '/EHsc'],
27+
'unix': ['-std=c++17', '-pthread'],
2828
}
2929

3030
extra_link_args = {
3131
'msvc': [],
32-
'unix': ['-std=c++11'],
32+
'unix': ['-std=c++17'],
3333
}
3434

3535

@@ -60,6 +60,7 @@ def build_extensions(self):
6060
include_dirs=[
6161
numpy.get_include(),
6262
dimod.get_include(),
63+
"extern/taskflow/",
6364
],
6465
install_requires=[
6566
'numpy>=1.20.0,<2.0.0', # keep synced with circle-ci, pyproject.toml

tests/test_presolve.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
from dwave.preprocessing import Presolver, InfeasibleModelError
2121

2222

23+
class TestExperiment(unittest.TestCase):
24+
def test_parallel(self):
25+
cqm = dimod.CQM()
26+
for _ in range(100):
27+
cqm.add_constraint(dimod.BQM("BINARY") == 1)
28+
29+
presolver = Presolver(cqm)
30+
self.assertLessEqual(presolver.apply_parallel(), 55) # should take 100s
31+
32+
2333
class TestPresolver(unittest.TestCase):
2434
def test_bug0(self):
2535
random = np.random.RandomState(0)

testscpp/Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ ROOT := ../
22
SRC := $(ROOT)/dwave/preprocessing/
33
CATCH2 := $(ROOT)/testscpp/Catch2/single_include/
44
DIMOD := $(shell python -c 'import dimod; print(dimod.get_include())')
5+
TASKFLOW := $(ROOT)/extern/taskflow/
56

67
all: catch2 test_main test_main_parallel tests tests_parallel
78

@@ -12,12 +13,12 @@ tests_parallel: test_main_parallel.out
1213
./test_main_parallel
1314

1415
test_main: test_main.cpp
15-
g++ -std=c++11 -Wall -c test_main.cpp
16-
g++ -std=c++11 -Wall test_main.o tests/*.cpp -o test_main -I $(SRC)/include/ -I $(DIMOD) -I $(CATCH2)
16+
g++ -std=c++17 -Wall -pthread -c test_main.cpp
17+
g++ -std=c++17 -Wall -pthread test_main.o tests/*.cpp -o test_main -I $(SRC)/include/ -I $(DIMOD) -I $(CATCH2) -I $(TASKFLOW)
1718

1819
test_main_parallel: test_main.cpp
19-
g++ -std=c++11 -fopenmp -Wall -c test_main.cpp -o test_main_parallel.o
20-
g++ -std=c++11 -fopenmp -Wall test_main_parallel.o tests/*.cpp -o test_main_parallel -I $(SRC)/include/ -I $(DIMOD) -I $(CATCH2)
20+
g++ -std=c++17 -fopenmp -Wall -c test_main.cpp -o test_main_parallel.o
21+
g++ -std=c++17 -fopenmp -Wall test_main_parallel.o tests/*.cpp -o test_main_parallel -I $(SRC)/include/ -I $(DIMOD) -I $(CATCH2) -I $(TASKFLOW)
2122

2223
catch2:
2324
git submodule init

0 commit comments

Comments
 (0)