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.
Files changed (124) hide show
  1. {eqc_models-0.9.9/eqc_models.egg-info → eqc_models-0.10.1}/PKG-INFO +2 -1
  2. eqc_models-0.10.1/compile_extensions.py +67 -0
  3. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/pygments.css +18 -18
  4. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/dependencies.rst +1 -0
  5. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/eqc_models.rst +8 -0
  6. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/penaltymultiplier.py +20 -7
  7. eqc_models-0.10.1/eqc_models/combinatorics/__init__.py +5 -0
  8. eqc_models-0.10.1/eqc_models/combinatorics/setcover.py +94 -0
  9. eqc_models-0.10.1/eqc_models/graph/__init__.py +6 -0
  10. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/base.py +28 -17
  11. eqc_models-0.10.1/eqc_models/graph/partition.py +148 -0
  12. eqc_models-0.10.1/eqc_models/ml/classifierqboost.py +628 -0
  13. eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian.pyx +83 -0
  14. eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian_c_func.c +68 -0
  15. eqc_models-0.10.1/eqc_models/ml/cvqboost_hamiltonian_c_func.h +14 -0
  16. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/polynomial.py +11 -0
  17. {eqc_models-0.9.9 → eqc_models-0.10.1/eqc_models.egg-info}/PKG-INFO +2 -1
  18. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/SOURCES.txt +10 -0
  19. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/requires.txt +1 -0
  20. {eqc_models-0.9.9 → eqc_models-0.10.1}/pyproject.toml +1 -0
  21. eqc_models-0.10.1/scripts/graph_partitioning.py +21 -0
  22. eqc_models-0.10.1/test/testcvqboost.py +49 -0
  23. eqc_models-0.10.1/test/testgraphpartitionmodel.py +147 -0
  24. eqc_models-0.10.1/test/testsetcovermodel.py +25 -0
  25. eqc_models-0.9.9/compile_extensions.py +0 -23
  26. eqc_models-0.9.9/eqc_models/graph/__init__.py +0 -5
  27. eqc_models-0.9.9/eqc_models/ml/classifierqboost.py +0 -423
  28. {eqc_models-0.9.9 → eqc_models-0.10.1}/.gitlab-ci.yml +0 -0
  29. {eqc_models-0.9.9 → eqc_models-0.10.1}/LICENSE.txt +0 -0
  30. {eqc_models-0.9.9 → eqc_models-0.10.1}/MANIFEST.in +0 -0
  31. {eqc_models-0.9.9 → eqc_models-0.10.1}/README.md +0 -0
  32. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/Makefile +0 -0
  33. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/basic.css +0 -0
  34. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/css/badge_only.css +0 -0
  35. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/css/theme.css +0 -0
  36. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/custom.css +0 -0
  37. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/file.png +0 -0
  38. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/minus.png +0 -0
  39. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/plus.png +0 -0
  40. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/build/html/_static/white_logo.png +0 -0
  41. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/make.bat +0 -0
  42. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/_static/custom.css +0 -0
  43. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/_static/white_logo.png +0 -0
  44. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/conf.py +0 -0
  45. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/index.rst +0 -0
  46. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/modules.rst +0 -0
  47. {eqc_models-0.9.9 → eqc_models-0.10.1}/docs/source/usage.rst +0 -0
  48. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/__init__.py +0 -0
  49. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/__init__.py +0 -0
  50. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/algorithms/base.py +0 -0
  51. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/__init__.py +0 -0
  52. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/allocation.py +0 -0
  53. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/portbase.py +0 -0
  54. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/allocation/portmomentum.py +0 -0
  55. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/__init__.py +0 -0
  56. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/qap.py +0 -0
  57. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/assignment/setpartition.py +0 -0
  58. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/__init__.py +0 -0
  59. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/base.py +0 -0
  60. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/constraints.py +0 -0
  61. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/operators.py +0 -0
  62. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polyeval.c +0 -0
  63. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polyeval.pyx +0 -0
  64. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/polynomial.py +0 -0
  65. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/base/quadratic.py +0 -0
  66. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/decoding.py +0 -0
  67. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/hypergraph.py +0 -0
  68. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/maxcut.py +0 -0
  69. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/graph/maxkcut.py +0 -0
  70. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/__init__.py +0 -0
  71. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/classifierbase.py +0 -0
  72. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/classifierqsvm.py +0 -0
  73. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/clustering.py +0 -0
  74. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/clusteringbase.py +0 -0
  75. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/decomposition.py +0 -0
  76. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/forecast.py +0 -0
  77. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/forecastbase.py +0 -0
  78. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/regressor.py +0 -0
  79. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/regressorbase.py +0 -0
  80. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/ml/reservoir.py +0 -0
  81. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/sequence/__init__.py +0 -0
  82. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/sequence/tsp.py +0 -0
  83. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/solvers/__init__.py +0 -0
  84. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/solvers/qciclient.py +0 -0
  85. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/__init__.py +0 -0
  86. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/fileio.py +0 -0
  87. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models/utilities/qplib.py +0 -0
  88. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/dependency_links.txt +0 -0
  89. {eqc_models-0.9.9 → eqc_models-0.10.1}/eqc_models.egg-info/top_level.txt +0 -0
  90. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/binary_job_example.py +0 -0
  91. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/c6h6_graph_clustering.py +0 -0
  92. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/clustering.py +0 -0
  93. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/continuous_job_example.py +0 -0
  94. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/duality_example.py +0 -0
  95. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/graph_clustering.py +0 -0
  96. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/hamiltonian_to_polynomial.py +0 -0
  97. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/hypergraph.py +0 -0
  98. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/integer_job_example.py +0 -0
  99. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/karate_graph_clustering.py +0 -0
  100. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/lin_reg_dirac3.py +0 -0
  101. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/mackey_glass_cell_production_series.csv +0 -0
  102. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/pca_iris_dirac3.py +0 -0
  103. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/port_opt_dirac3.py +0 -0
  104. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qboost_iris_dirac3.py +0 -0
  105. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_benchmark_config.py +0 -0
  106. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_reader.py +0 -0
  107. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qplib_runner.py +0 -0
  108. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/qsvm_iris_dirac3.py +0 -0
  109. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/reservoir_forecast.py +0 -0
  110. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/rundoctests.py +0 -0
  111. {eqc_models-0.9.9 → eqc_models-0.10.1}/scripts/utils.py +0 -0
  112. {eqc_models-0.9.9 → eqc_models-0.10.1}/setup.cfg +0 -0
  113. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/doctest_base.py +0 -0
  114. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testallocationmodel.py +0 -0
  115. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testconstraint.py +0 -0
  116. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testeqcdirectsolver.py +0 -0
  117. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testhypergraphmodel.py +0 -0
  118. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testmaxcutmodel.py +0 -0
  119. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testpolynomialmodel.py +0 -0
  120. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testqapmodel.py +0 -0
  121. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testqciclientsolver.py +0 -0
  122. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testquadraticmodel.py +0 -0
  123. {eqc_models-0.9.9 → eqc_models-0.10.1}/test/testsetpartitionmodel.py +0 -0
  124. {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.9.9
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 #FF0000 } /* Error */
9
+ .highlight .err { border: 1px solid #F00 } /* Error */
10
10
  .highlight .k { color: #008000; font-weight: bold } /* Keyword */
11
- .highlight .o { color: #666666 } /* Operator */
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: #0044DD } /* Generic.Traceback */
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: #666666 } /* Literal.Number */
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: #0000FF; font-weight: bold } /* Name.Class */
40
- .highlight .no { color: #880000 } /* Name.Constant */
41
- .highlight .nd { color: #AA22FF } /* Name.Decorator */
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: #0000FF } /* Name.Function */
44
+ .highlight .nf { color: #00F } /* Name.Function */
45
45
  .highlight .nl { color: #767600 } /* Name.Label */
46
- .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
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: #AA22FF; font-weight: bold } /* Operator.Word */
50
- .highlight .w { color: #bbbbbb } /* Text.Whitespace */
51
- .highlight .mb { color: #666666 } /* Literal.Number.Bin */
52
- .highlight .mf { color: #666666 } /* Literal.Number.Float */
53
- .highlight .mh { color: #666666 } /* Literal.Number.Hex */
54
- .highlight .mi { color: #666666 } /* Literal.Number.Integer */
55
- .highlight .mo { color: #666666 } /* Literal.Number.Oct */
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: #0000FF } /* Name.Function.Magic */
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: #666666 } /* Literal.Number.Integer.Long */
75
+ .highlight .il { color: #666 } /* Literal.Number.Integer.Long */
@@ -9,5 +9,6 @@ Packages
9
9
  - ``numpy>=1.22.1, <2``
10
10
  - ``networkx>=2.6.3, <3``
11
11
  - ``pandas>=2.1.0``
12
+ - ``scikit-learn>=1.2.1``
12
13
  - ``qci-client>=4.3.0, <5``
13
14
  - ``emucore-direct==1.0.6``
@@ -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 Dirac3CloudSolver
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 = Dirac3CloudSolver() # must be configured with environment variables
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, mean_photon_number=0.15, normalized_loss_rate=4, num_samples=5) # doctest: +ELLIPSIS
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 > 1e-6:
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 obj_val < ub:
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) < 1e-4:
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,5 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+
3
+ from .setcover import SetCoverModel
4
+
5
+ __all__ = ["SetCoverModel"]
@@ -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
@@ -0,0 +1,6 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+
3
+ from .maxcut import MaxCutModel
4
+ from .partition import GraphPartitionModel
5
+
6
+ __all__ = ["MaxCutModel", "GraphPartitionModel"]
@@ -7,7 +7,34 @@ class GraphModel(QuadraticModel):
7
7
  """ """
8
8
  def __init__(self, G : nx.Graph):
9
9
  self.G = G
10
- self.linear_objective, self.quad_objective = self.costFunction()
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