eqc-models 0.9.9__tar.gz → 0.10.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {eqc_models-0.9.9/eqc_models.egg-info → eqc_models-0.10.1}/PKG-INFO +2 -1
- eqc_models-0.10.1/compile_extensions.py +67 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/pygments.css +18 -18
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/dependencies.rst +1 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/eqc_models.rst +8 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/penaltymultiplier.py +20 -7
- eqc_models-0.10.1/eqc_models/combinatorics/__init__.py +5 -0
- eqc_models-0.10.1/eqc_models/combinatorics/setcover.py +94 -0
- eqc_models-0.10.1/eqc_models/graph/__init__.py +6 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/base.py +28 -17
- eqc_models-0.10.1/eqc_models/graph/partition.py +148 -0
- eqc_models-0.10.1/eqc_models/ml/classifierqboost.py +628 -0
- eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian.pyx +83 -0
- eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian_c_func.c +68 -0
- eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian_c_func.h +14 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/polynomial.py +11 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1/eqc_models.egg-info}/PKG-INFO +2 -1
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/SOURCES.txt +10 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/requires.txt +1 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/pyproject.toml +1 -0
- eqc_models-0.10.1/scripts/graph_partitioning.py +21 -0
- eqc_models-0.10.1/test/testcvqboost.py +49 -0
- eqc_models-0.10.1/test/testgraphpartitionmodel.py +147 -0
- eqc_models-0.10.1/test/testsetcovermodel.py +25 -0
- eqc_models-0.9.9/compile_extensions.py +0 -23
- eqc_models-0.9.9/eqc_models/graph/__init__.py +0 -5
- eqc_models-0.9.9/eqc_models/ml/classifierqboost.py +0 -423
- {eqc_models-0.9.9 → eqc_models-0.10.1}/.gitlab-ci.yml +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/LICENSE.txt +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/MANIFEST.in +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/README.md +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/Makefile +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/basic.css +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/css/badge_only.css +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/css/theme.css +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/custom.css +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/file.png +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/minus.png +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/plus.png +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/white_logo.png +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/make.bat +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/_static/custom.css +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/_static/white_logo.png +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/conf.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/index.rst +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/modules.rst +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/usage.rst +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/base.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/allocation.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/portbase.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/portmomentum.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/qap.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/setpartition.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/base.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/constraints.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/operators.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polyeval.c +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polyeval.pyx +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polynomial.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/quadratic.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/decoding.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/hypergraph.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/maxcut.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/maxkcut.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/classifierbase.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/classifierqsvm.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/clustering.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/clusteringbase.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/decomposition.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/forecast.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/forecastbase.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/regressor.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/regressorbase.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/reservoir.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/sequence/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/sequence/tsp.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/solvers/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/solvers/qciclient.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/__init__.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/fileio.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/qplib.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/dependency_links.txt +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/top_level.txt +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/binary_job_example.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/c6h6_graph_clustering.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/clustering.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/continuous_job_example.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/duality_example.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/graph_clustering.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/hamiltonian_to_polynomial.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/hypergraph.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/integer_job_example.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/karate_graph_clustering.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/lin_reg_dirac3.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/mackey_glass_cell_production_series.csv +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/pca_iris_dirac3.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/port_opt_dirac3.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qboost_iris_dirac3.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_benchmark_config.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_reader.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_runner.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qsvm_iris_dirac3.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/reservoir_forecast.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/rundoctests.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/utils.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/setup.cfg +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/doctest_base.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testallocationmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testconstraint.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testeqcdirectsolver.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testhypergraphmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testmaxcutmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testpolynomialmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testqapmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testqciclientsolver.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testquadraticmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testsetpartitionmodel.py +0 -0
- {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testtsp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: eqc-models
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: Optimization and ML modeling package targeting EQC devices
|
|
5
5
|
Author: Quantum Computing Inc.
|
|
6
6
|
Author-email: support@quantumcomputinginc.com
|
|
@@ -13,6 +13,7 @@ License-File: LICENSE.txt
|
|
|
13
13
|
Requires-Dist: numpy<2,>=1.22.1
|
|
14
14
|
Requires-Dist: networkx<3,>=2.6.3
|
|
15
15
|
Requires-Dist: pandas>=2.1.0
|
|
16
|
+
Requires-Dist: scikit-learn>=1.2.1
|
|
16
17
|
Requires-Dist: qci-client<5,>=4.3.0
|
|
17
18
|
Requires-Dist: emucore-direct==1.0.6
|
|
18
19
|
Provides-Extra: direct
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from setuptools import Extension
|
|
4
|
+
from setuptools.command.build_py import build_py as _build_py
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
# # Set cvqboost compile args
|
|
8
|
+
# if sys.platform == "darwin":
|
|
9
|
+
# openmp_prefix = os.environ.get(
|
|
10
|
+
# "LIBOMP_PREFIX", "/opt/homebrew/opt/libomp"
|
|
11
|
+
# )
|
|
12
|
+
# openmp_include = os.path.join(openmp_prefix, "include")
|
|
13
|
+
# openmp_lib = os.path.join(openmp_prefix, "lib", "libomp.a")
|
|
14
|
+
# extra_compile_args_cvq = [
|
|
15
|
+
# "-Xpreprocessor",
|
|
16
|
+
# "-fopenmp",
|
|
17
|
+
# "-O3",
|
|
18
|
+
# "-ffast-math",
|
|
19
|
+
# "-march=native",
|
|
20
|
+
# ]
|
|
21
|
+
# extra_link_args_cvq = [openmp_lib, "-O3", "-march=native"]
|
|
22
|
+
# elif sys.platform.startswith("linux"):
|
|
23
|
+
# extra_compile_args_cvq = [
|
|
24
|
+
# "-static-libgcc",
|
|
25
|
+
# "-fopenmp",
|
|
26
|
+
# "-O3",
|
|
27
|
+
# "-ffast-math",
|
|
28
|
+
# ]
|
|
29
|
+
# extra_link_args_cvq = [
|
|
30
|
+
# "-static-libgcc",
|
|
31
|
+
# "-static-libstdc++",
|
|
32
|
+
# "-fopenmp",
|
|
33
|
+
# "-O3",
|
|
34
|
+
# ]
|
|
35
|
+
# elif sys.platform == "win32":
|
|
36
|
+
# extra_compile_args_cvq = ["/openmp"]
|
|
37
|
+
# extra_link_args_cvq = []
|
|
38
|
+
|
|
39
|
+
# Modules to be compiled and include_dirs when necessary
|
|
40
|
+
extensions = [
|
|
41
|
+
Extension(
|
|
42
|
+
"eqc_models.base.polyeval",
|
|
43
|
+
["eqc_models/base/polyeval.pyx"],
|
|
44
|
+
include_dirs=[numpy.get_include()],
|
|
45
|
+
extra_compile_args=["-O3", "-ffast-math"],
|
|
46
|
+
),
|
|
47
|
+
# Extension(
|
|
48
|
+
# "eqc_models.ml.cvqboost_hamiltonian",
|
|
49
|
+
# ["eqc_models/ml/cvqboost_hamiltonian.pyx"],
|
|
50
|
+
# include_dirs=[numpy.get_include()],
|
|
51
|
+
# extra_compile_args=extra_compile_args_cvq,
|
|
52
|
+
# extra_link_args=extra_link_args_cvq,
|
|
53
|
+
# ),
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class build_py(_build_py):
|
|
58
|
+
def run(self):
|
|
59
|
+
self.run_command("build_ext")
|
|
60
|
+
return super().run()
|
|
61
|
+
|
|
62
|
+
def initialize_options(self):
|
|
63
|
+
super().initialize_options()
|
|
64
|
+
if self.distribution.ext_modules == None:
|
|
65
|
+
self.distribution.ext_modules = []
|
|
66
|
+
|
|
67
|
+
self.distribution.ext_modules.extend(extensions)
|
|
@@ -6,9 +6,9 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
|
|
|
6
6
|
.highlight .hll { background-color: #ffffcc }
|
|
7
7
|
.highlight { background: #f8f8f8; }
|
|
8
8
|
.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
|
|
9
|
-
.highlight .err { border: 1px solid #
|
|
9
|
+
.highlight .err { border: 1px solid #F00 } /* Error */
|
|
10
10
|
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
|
|
11
|
-
.highlight .o { color: #
|
|
11
|
+
.highlight .o { color: #666 } /* Operator */
|
|
12
12
|
.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
|
13
13
|
.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
|
14
14
|
.highlight .cp { color: #9C6500 } /* Comment.Preproc */
|
|
@@ -25,34 +25,34 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
|
|
|
25
25
|
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
|
26
26
|
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
|
27
27
|
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
|
28
|
-
.highlight .gt { color: #
|
|
28
|
+
.highlight .gt { color: #04D } /* Generic.Traceback */
|
|
29
29
|
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
|
30
30
|
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
|
31
31
|
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
|
32
32
|
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
|
|
33
33
|
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
|
34
34
|
.highlight .kt { color: #B00040 } /* Keyword.Type */
|
|
35
|
-
.highlight .m { color: #
|
|
35
|
+
.highlight .m { color: #666 } /* Literal.Number */
|
|
36
36
|
.highlight .s { color: #BA2121 } /* Literal.String */
|
|
37
37
|
.highlight .na { color: #687822 } /* Name.Attribute */
|
|
38
38
|
.highlight .nb { color: #008000 } /* Name.Builtin */
|
|
39
|
-
.highlight .nc { color: #
|
|
40
|
-
.highlight .no { color: #
|
|
41
|
-
.highlight .nd { color: #
|
|
39
|
+
.highlight .nc { color: #00F; font-weight: bold } /* Name.Class */
|
|
40
|
+
.highlight .no { color: #800 } /* Name.Constant */
|
|
41
|
+
.highlight .nd { color: #A2F } /* Name.Decorator */
|
|
42
42
|
.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
|
|
43
43
|
.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
|
44
|
-
.highlight .nf { color: #
|
|
44
|
+
.highlight .nf { color: #00F } /* Name.Function */
|
|
45
45
|
.highlight .nl { color: #767600 } /* Name.Label */
|
|
46
|
-
.highlight .nn { color: #
|
|
46
|
+
.highlight .nn { color: #00F; font-weight: bold } /* Name.Namespace */
|
|
47
47
|
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
|
|
48
48
|
.highlight .nv { color: #19177C } /* Name.Variable */
|
|
49
|
-
.highlight .ow { color: #
|
|
50
|
-
.highlight .w { color: #
|
|
51
|
-
.highlight .mb { color: #
|
|
52
|
-
.highlight .mf { color: #
|
|
53
|
-
.highlight .mh { color: #
|
|
54
|
-
.highlight .mi { color: #
|
|
55
|
-
.highlight .mo { color: #
|
|
49
|
+
.highlight .ow { color: #A2F; font-weight: bold } /* Operator.Word */
|
|
50
|
+
.highlight .w { color: #BBB } /* Text.Whitespace */
|
|
51
|
+
.highlight .mb { color: #666 } /* Literal.Number.Bin */
|
|
52
|
+
.highlight .mf { color: #666 } /* Literal.Number.Float */
|
|
53
|
+
.highlight .mh { color: #666 } /* Literal.Number.Hex */
|
|
54
|
+
.highlight .mi { color: #666 } /* Literal.Number.Integer */
|
|
55
|
+
.highlight .mo { color: #666 } /* Literal.Number.Oct */
|
|
56
56
|
.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
|
|
57
57
|
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
|
|
58
58
|
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
|
|
@@ -67,9 +67,9 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
|
|
|
67
67
|
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
|
|
68
68
|
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
|
|
69
69
|
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
|
|
70
|
-
.highlight .fm { color: #
|
|
70
|
+
.highlight .fm { color: #00F } /* Name.Function.Magic */
|
|
71
71
|
.highlight .vc { color: #19177C } /* Name.Variable.Class */
|
|
72
72
|
.highlight .vg { color: #19177C } /* Name.Variable.Global */
|
|
73
73
|
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
|
|
74
74
|
.highlight .vm { color: #19177C } /* Name.Variable.Magic */
|
|
75
|
-
.highlight .il { color: #
|
|
75
|
+
.highlight .il { color: #666 } /* Literal.Number.Integer.Long */
|
|
@@ -38,6 +38,14 @@ eqc\_models.assignment
|
|
|
38
38
|
:undoc-members:
|
|
39
39
|
:show-inheritance:
|
|
40
40
|
|
|
41
|
+
eqc\_models.combinatorics
|
|
42
|
+
--------------------------
|
|
43
|
+
|
|
44
|
+
.. automodule:: eqc_models.combinatorics
|
|
45
|
+
:members:
|
|
46
|
+
:undoc-members:
|
|
47
|
+
:show-inheritance:
|
|
48
|
+
|
|
41
49
|
eqc\_models.graph
|
|
42
50
|
--------------------
|
|
43
51
|
|
|
@@ -33,6 +33,14 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
33
33
|
penalties : List
|
|
34
34
|
The values for penalties found at each algorithm iteration. A penalty of 0
|
|
35
35
|
indicates algorithm termination.
|
|
36
|
+
penalty_threshold : float
|
|
37
|
+
This value is the cutoff for penalty values that are threated as 0. Default
|
|
38
|
+
is 1e-6.
|
|
39
|
+
progress_threshold : float
|
|
40
|
+
This value is the cutoff for checking for progress on reducing the penalty
|
|
41
|
+
value. The current penalty is compared to the average of the previous two
|
|
42
|
+
and if the absolute difference is less than this value, then the algorithm
|
|
43
|
+
stops, reporting progress has not been made. The default value is 1e-4.
|
|
36
44
|
dynamic_range : List
|
|
37
45
|
The values for the dynamic range of the unconstrained problem formulation,
|
|
38
46
|
which is useful for identifying difficulty in representation of the problem
|
|
@@ -50,7 +58,7 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
50
58
|
This example uses the quadratic assignment problem and the known multiplier to test
|
|
51
59
|
the implementation of the algorithm.
|
|
52
60
|
|
|
53
|
-
>>> from eqc_models.solvers.qciclient import
|
|
61
|
+
>>> from eqc_models.solvers.qciclient import Dirac3IntegerCloudSolver
|
|
54
62
|
>>> from eqc_models.assignment.qap import QAPModel
|
|
55
63
|
>>> A = np.array([[0, 5, 8, 0, 1],
|
|
56
64
|
... [0, 0, 0, 10, 15],
|
|
@@ -68,10 +76,10 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
68
76
|
... [7, 5, 8, 5, 7],
|
|
69
77
|
... [1, 9, 2, 9, 2.]])
|
|
70
78
|
>>> model = QAPModel(A, B, C)
|
|
71
|
-
>>> solver =
|
|
79
|
+
>>> solver = Dirac3IntegerCloudSolver() # must be configured with environment variables
|
|
72
80
|
>>> algo = PenaltyMultiplierAlgorithm(model, solver)
|
|
73
81
|
>>> algo.upper_bound = 330.64
|
|
74
|
-
>>> algo.run(relaxation_schedule=2,
|
|
82
|
+
>>> algo.run(relaxation_schedule=2, num_samples=5) # doctest: +ELLIPSIS
|
|
75
83
|
2... RUNNING... COMPLETED...
|
|
76
84
|
>>> algo.alphas[-1] # doctest: +SKIP
|
|
77
85
|
106.25
|
|
@@ -80,7 +88,8 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
80
88
|
|
|
81
89
|
"""
|
|
82
90
|
|
|
83
|
-
def __init__(self, model : ConstraintModel, solver : ModelSolver
|
|
91
|
+
def __init__(self, model : ConstraintModel, solver : ModelSolver, penalty_threshold:float=1e-6,
|
|
92
|
+
progress_threshold : float = 1e-4):
|
|
84
93
|
self.model = model
|
|
85
94
|
self.solver = solver
|
|
86
95
|
# ub = np.max(model.quad_objective)
|
|
@@ -95,6 +104,8 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
95
104
|
self.alphas = None
|
|
96
105
|
self.dynamic_range = None
|
|
97
106
|
self.responses = None
|
|
107
|
+
self.penalty_threshold = penalty_threshold
|
|
108
|
+
self.progress_threshold = progress_threshold
|
|
98
109
|
|
|
99
110
|
@property
|
|
100
111
|
def upper_bound(self) -> float:
|
|
@@ -141,7 +152,7 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
141
152
|
else:
|
|
142
153
|
penalty = None
|
|
143
154
|
|
|
144
|
-
while penalty is None or penalty >
|
|
155
|
+
while penalty is None or penalty > self.penalty_threshold:
|
|
145
156
|
log.info("NEW RUN")
|
|
146
157
|
log.info("SETTING MULTIPLIER %f", alpha)
|
|
147
158
|
model.penalty_multiplier = float(alpha)
|
|
@@ -162,8 +173,10 @@ class PenaltyMultiplierAlgorithm(Algorithm):
|
|
|
162
173
|
energies.append(results["energies"][0])
|
|
163
174
|
log.info("NEW SOLUTION OBJECTIVE %f LESS OFFSET %f ENERGY %f PENALTY %f",
|
|
164
175
|
obj_val, less_offset, energies[-1], penalty)
|
|
165
|
-
if
|
|
176
|
+
if penalty < self.penalty_threshold:
|
|
177
|
+
pass
|
|
178
|
+
elif obj_val < ub:
|
|
166
179
|
alpha += (ub - obj_val) / penalty
|
|
167
|
-
if abs(sum(penalties[-2:])/2-penalty) <
|
|
180
|
+
if penalty > self.penalty_threshold and abs(sum(penalties[-2:])/2-penalty) < self.progress_threshold:
|
|
168
181
|
log.warn("SUFFICIENT PROGRESS NOT MADE FOR THREE ITERATIONS, QUITTING")
|
|
169
182
|
break
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
SetCoverModel solves the mathematical programming problem
|
|
3
|
+
|
|
4
|
+
$$
|
|
5
|
+
\mathrm{minimize}_x \sum_{x_i:X_i \in X} c_i x_i
|
|
6
|
+
$$
|
|
7
|
+
|
|
8
|
+
Subject to
|
|
9
|
+
|
|
10
|
+
$$
|
|
11
|
+
\sum_{i:a\in X_i} x_j \geq 1 \, \forall a \in A}
|
|
12
|
+
$$$
|
|
13
|
+
|
|
14
|
+
and
|
|
15
|
+
|
|
16
|
+
$$
|
|
17
|
+
x_i \in \{0, 1\} \forall {x_i: X_i \in X}
|
|
18
|
+
$$
|
|
19
|
+
|
|
20
|
+
Where $S$ is a set of all elements, $X$ is a collection of sets $X_i$, and the union of all is equal to $S$.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from typing import List
|
|
25
|
+
import numpy as np
|
|
26
|
+
from eqc_models.base import ConstrainedQuadraticModel
|
|
27
|
+
|
|
28
|
+
class SetCoverModel(ConstrainedQuadraticModel):
|
|
29
|
+
"""
|
|
30
|
+
Parameters
|
|
31
|
+
-------------
|
|
32
|
+
|
|
33
|
+
subsets : List
|
|
34
|
+
List of sets where the union of all sets is S
|
|
35
|
+
|
|
36
|
+
weights : List
|
|
37
|
+
List of weights where each weight is the cost of choosing the subset
|
|
38
|
+
corresponding to the index of the weight.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
>>> X = [set(['A', 'B']), set(['B', 'C']), set(['C'])]
|
|
42
|
+
>>> weights = [2, 2, 1]
|
|
43
|
+
>>> model = SetCoverModel(X, weights)
|
|
44
|
+
>>> model.penalty_multiplier = 2
|
|
45
|
+
>>> from eqc_models.solvers import Dirac3IntegerCloudSolver
|
|
46
|
+
>>> solver = Dirac3IntegerCloudSolver()
|
|
47
|
+
>>> response = solver.solve(model, relaxation_schedule=1, num_samples=5) #doctest: +ELLIPSIS
|
|
48
|
+
20...
|
|
49
|
+
>>> solutions = response["results"]["solutions"]
|
|
50
|
+
>>> solutions[0]
|
|
51
|
+
[1, 0, 1, 0, 0, 0]
|
|
52
|
+
>>> model.decode(solutions[0])
|
|
53
|
+
[{'B', 'A'}, {'C'}]
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, subsets, weights):
|
|
58
|
+
# ensure that X is ordered
|
|
59
|
+
self.X = X = list(subsets)
|
|
60
|
+
self.S = S = set()
|
|
61
|
+
|
|
62
|
+
for x in subsets:
|
|
63
|
+
S = S.union(x)
|
|
64
|
+
# elements is sorted to maintain consistent output
|
|
65
|
+
elements = [a for a in S]
|
|
66
|
+
elements.sort()
|
|
67
|
+
# constraints
|
|
68
|
+
A = []
|
|
69
|
+
b = []
|
|
70
|
+
variables = [f'x_{i}' for i in range(len(X))]
|
|
71
|
+
pos = 0
|
|
72
|
+
for a in elements:
|
|
73
|
+
variables.append(f"s_{pos}")
|
|
74
|
+
constraint = [1 if a in X[i] else 0 for i in range(len(X))]
|
|
75
|
+
slacks = [0 for i in range(len(S))]
|
|
76
|
+
slacks[pos] = -1
|
|
77
|
+
A.append(constraint + slacks)
|
|
78
|
+
pos += 1
|
|
79
|
+
b.append(1)
|
|
80
|
+
n = len(variables)
|
|
81
|
+
J = np.zeros((n, n))
|
|
82
|
+
h = np.zeros((n, ))
|
|
83
|
+
h[:len(weights)] = weights
|
|
84
|
+
# call the superclass constructor with the objective and constraints
|
|
85
|
+
super(SetCoverModel, self).__init__(h, J, np.array(A), np.array(b))
|
|
86
|
+
# set upper bound on the variables to be 1 for x_i and the length of X minus 1 for the slacks
|
|
87
|
+
self.upper_bound = np.array([1 for i in range(len(weights))] + [len(X)-1 for i in range(n-len(weights))])
|
|
88
|
+
|
|
89
|
+
def decode(self, solution) -> List:
|
|
90
|
+
xbar = []
|
|
91
|
+
for i in range(len(self.X)):
|
|
92
|
+
if solution[i] > 0.5:
|
|
93
|
+
xbar.append(self.X[i])
|
|
94
|
+
return xbar
|
|
@@ -7,7 +7,34 @@ class GraphModel(QuadraticModel):
|
|
|
7
7
|
""" """
|
|
8
8
|
def __init__(self, G : nx.Graph):
|
|
9
9
|
self.G = G
|
|
10
|
-
|
|
10
|
+
super().__init__(*self.costFunction())
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def linear_objective(self):
|
|
14
|
+
"""Return linear terms as a vector."""
|
|
15
|
+
return self._H[0]
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def quad_objective(self):
|
|
19
|
+
"""Return quadratic terms as a matrix."""
|
|
20
|
+
return self._H[1]
|
|
21
|
+
|
|
22
|
+
def costFunction(self):
|
|
23
|
+
"""
|
|
24
|
+
Parameters
|
|
25
|
+
-------------
|
|
26
|
+
|
|
27
|
+
None
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
--------------
|
|
31
|
+
|
|
32
|
+
:C: linear operator (vector array of coefficients) for cost function
|
|
33
|
+
:J: quadratic operator (N by N matrix array of coefficients ) for cost function
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
raise NotImplementedError("GraphModel does not implement costFunction")
|
|
37
|
+
|
|
11
38
|
|
|
12
39
|
class NodeModel(GraphModel):
|
|
13
40
|
"""
|
|
@@ -22,22 +49,6 @@ class NodeModel(GraphModel):
|
|
|
22
49
|
names = [node for node in self.G.nodes]
|
|
23
50
|
names.sort()
|
|
24
51
|
return names
|
|
25
|
-
|
|
26
|
-
def costFunction(self):
|
|
27
|
-
"""
|
|
28
|
-
Parameters
|
|
29
|
-
-------------
|
|
30
|
-
|
|
31
|
-
None
|
|
32
|
-
|
|
33
|
-
Returns
|
|
34
|
-
--------------
|
|
35
|
-
|
|
36
|
-
:C: linear operator (vector array of coefficients) for cost function
|
|
37
|
-
:J: quadratic operator (N by N matrix array of coefficients ) for cost function
|
|
38
|
-
|
|
39
|
-
"""
|
|
40
|
-
raise NotImplementedError("NodeModel does not implement costFunction")
|
|
41
52
|
|
|
42
53
|
def modularity(self, partition : Set[Set]) -> float:
|
|
43
54
|
""" Calculate modularity from a partition (set of communities) """
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
import numpy as np
|
|
3
|
+
import scipy.sparse as sp
|
|
4
|
+
import networkx as nx
|
|
5
|
+
from math import modf
|
|
6
|
+
from eqc_models.graph.base import GraphModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GraphPartitionModel(GraphModel):
|
|
10
|
+
"""
|
|
11
|
+
A model for graph partitioning into `k` parts with objective and constraints
|
|
12
|
+
derived from the Laplacian matrix and additional penalties for balance and constraints.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, G: nx.Graph, k: int = 2, weight: str = "weight", alpha: float = 1.0, beta_obj: float = 1.0,
|
|
16
|
+
gamma: float = 1.0):
|
|
17
|
+
"""
|
|
18
|
+
Parameters:
|
|
19
|
+
-----------
|
|
20
|
+
G : nx.Graph
|
|
21
|
+
The graph to partition.
|
|
22
|
+
k : int
|
|
23
|
+
The number of partitions.
|
|
24
|
+
weight : str
|
|
25
|
+
The key for edge weights in the graph.
|
|
26
|
+
alpha : float
|
|
27
|
+
The penalty multiplier for balance constraints.
|
|
28
|
+
beta_obj : float
|
|
29
|
+
The penalty multiplier for minimizing edge cuts (Laplacian term).
|
|
30
|
+
gamma : float
|
|
31
|
+
The penalty multiplier for assignment constraints.
|
|
32
|
+
"""
|
|
33
|
+
self._G = G
|
|
34
|
+
self._k = k
|
|
35
|
+
self._weight = weight
|
|
36
|
+
self._alpha = alpha
|
|
37
|
+
self._beta_obj = beta_obj
|
|
38
|
+
self._gamma = gamma
|
|
39
|
+
self._laplacian = nx.laplacian_matrix(G, weight=weight)
|
|
40
|
+
self._num_nodes = G.number_of_nodes()
|
|
41
|
+
self._sorted_nodes = sorted(G.nodes)
|
|
42
|
+
self._constraints_offset = 0
|
|
43
|
+
self._balanced_partition_offset = 0
|
|
44
|
+
self.set_and_validate_k()
|
|
45
|
+
self._objective_matrix = self.initialize_model()
|
|
46
|
+
super().__init__(self._G)
|
|
47
|
+
|
|
48
|
+
def set_and_validate_k(self):
|
|
49
|
+
"""
|
|
50
|
+
Sets k and encoding length for a graph problem
|
|
51
|
+
"""
|
|
52
|
+
# modf(x) = (fractional, integer) decomposition.
|
|
53
|
+
# Make sure fractional portion is zero. Convert to int if so.
|
|
54
|
+
assert modf(self._k)[0] == 0, "'k' must be an integer."
|
|
55
|
+
|
|
56
|
+
# it's an int, so set self.k
|
|
57
|
+
self._k = int(self._k)
|
|
58
|
+
|
|
59
|
+
# Verify k >= 2
|
|
60
|
+
assert self._k >= 2, f"ERROR, k={self._k}: k must be greater than or equal to 2."
|
|
61
|
+
|
|
62
|
+
# Verify that k makes sense
|
|
63
|
+
assert self._k <= self._num_nodes, (
|
|
64
|
+
f"ERROR, k={self._k}: k must be less than number of nodes or variables. k = {self._k} and "
|
|
65
|
+
f"number of nodes = {self._num_nodes}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def initialize_model(self):
|
|
69
|
+
"""
|
|
70
|
+
Build the objective matrix and constraints for the k-partition problem.
|
|
71
|
+
"""
|
|
72
|
+
if self._k == 2:
|
|
73
|
+
# For 2 partitions, construct a simpler QUBO from the Laplacian matrix
|
|
74
|
+
return self.get_two_partition_qubo()
|
|
75
|
+
else:
|
|
76
|
+
# For k > 2, construct a block-diagonal Laplacian with balance and constraints
|
|
77
|
+
laplacian_blocks = 0.5 * sp.block_diag([self._laplacian] * self._k, format="csr")
|
|
78
|
+
balance_term = self.get_balanced_partition_term()
|
|
79
|
+
constraints = self.get_constraints()
|
|
80
|
+
return (
|
|
81
|
+
self._alpha * balance_term
|
|
82
|
+
+ self._gamma * constraints
|
|
83
|
+
+ self._beta_obj * laplacian_blocks
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def get_balanced_partition_term(self) -> sp.spmatrix:
|
|
87
|
+
"""
|
|
88
|
+
Construct the quadratic penalty term for balanced partitions.
|
|
89
|
+
"""
|
|
90
|
+
I_k = sp.identity(self._k)
|
|
91
|
+
Ones_n = np.ones((self._num_nodes, self._num_nodes))
|
|
92
|
+
balanced_partition_term = sp.kron(I_k, Ones_n, format="csr")
|
|
93
|
+
balanced_partition_term -= (
|
|
94
|
+
2 * self._num_nodes / self._k * sp.identity(balanced_partition_term.shape[0])
|
|
95
|
+
)
|
|
96
|
+
self._balanced_partition_offset = self._num_nodes**2 / self._k
|
|
97
|
+
return balanced_partition_term
|
|
98
|
+
|
|
99
|
+
def get_constraints(self) -> sp.spmatrix:
|
|
100
|
+
"""
|
|
101
|
+
Construct the quadratic penalty term for assignment constraints.
|
|
102
|
+
"""
|
|
103
|
+
I_n = sp.identity(self._num_nodes)
|
|
104
|
+
Ones_k = np.ones((self._k, self._k))
|
|
105
|
+
constraints = sp.kron(Ones_k, I_n, format="csr")
|
|
106
|
+
constraints -= 2 * sp.identity(constraints.shape[0])
|
|
107
|
+
self._constraints_offset = self._num_nodes
|
|
108
|
+
return constraints
|
|
109
|
+
|
|
110
|
+
def get_two_partition_qubo(self) -> sp.spmatrix:
|
|
111
|
+
"""
|
|
112
|
+
Construct the QUBO matrix for two partitions using adjacency and penalties.
|
|
113
|
+
"""
|
|
114
|
+
Garr = nx.to_scipy_sparse_matrix(self._G, weight=self._weight, nodelist=self._sorted_nodes)
|
|
115
|
+
Q = (
|
|
116
|
+
self._alpha * np.ones(Garr.shape, dtype=np.float32)
|
|
117
|
+
- self._beta_obj * Garr
|
|
118
|
+
)
|
|
119
|
+
degrees = Garr.sum(axis=1).A1 # Convert sparse matrix to 1D array
|
|
120
|
+
diag = self._beta_obj * degrees - self._alpha * (self._num_nodes - 1)
|
|
121
|
+
np.fill_diagonal(Q, diag)
|
|
122
|
+
return sp.csr_matrix(Q)
|
|
123
|
+
|
|
124
|
+
def evaluate(self, solution: np.ndarray) -> float:
|
|
125
|
+
"""
|
|
126
|
+
Evaluate the objective function for a given solution.
|
|
127
|
+
"""
|
|
128
|
+
assert len(solution) == self._objective_matrix.shape[0], "Solution size mismatch."
|
|
129
|
+
return float(solution.T @ self._objective_matrix @ solution)
|
|
130
|
+
|
|
131
|
+
def decode(self, solution: np.ndarray) -> dict:
|
|
132
|
+
"""
|
|
133
|
+
Decode the solution vector into a partition assignment.
|
|
134
|
+
"""
|
|
135
|
+
if self._k == 2:
|
|
136
|
+
return {node: int(solution[i]) for i, node in enumerate(self._sorted_nodes)}
|
|
137
|
+
else:
|
|
138
|
+
partitions, nodes = np.where(solution.reshape((self._k, self._num_nodes)) == 1)
|
|
139
|
+
return {self._sorted_nodes[node]: int(partition) for partition, node in zip(partitions, nodes)}
|
|
140
|
+
|
|
141
|
+
def costFunction(self) -> Tuple[np.ndarray, np.ndarray]:
|
|
142
|
+
"""
|
|
143
|
+
Return the linear and quadratic components of the objective function.
|
|
144
|
+
"""
|
|
145
|
+
Q = self._objective_matrix
|
|
146
|
+
h = Q.diagonal()
|
|
147
|
+
J = 2 * sp.triu(Q, k=1).tocsr() # Extract upper triangular part for quadratic terms
|
|
148
|
+
return h, J
|