From 7cc6ab2d0d791b1ec418f8005be4a47ce4bab01d Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 27 May 2024 17:26:39 +0200 Subject: [PATCH 01/89] nox update --- noxfile.py | 4 +++- pyproject.toml | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/noxfile.py b/noxfile.py index 7f60553..03a0d9d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -23,18 +23,20 @@ "wheel>=0.40", "matplotlib>=3.8", "numpy>=1.23", + "sympy>=1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", "pytest==7.4.0", "scikit-learn>=1.3", "dimod>=0.12.0", + "docplex>=2.22", "dwave-preprocessing>=0.6.3 ", "dwave-samplers==1.2", "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", - "mesonpy>=0.10.0", + "pandas>=1.3", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 9e5e585..b0bcb6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,23 +19,21 @@ requires-python = ">=3.10,<3.12" dynamic = ["version"] dependencies = [ - "qubovert", - "sympy", - "numpy", - "pytest", - "dimod", - "dwave-samplers", - "dwave-system", + "qubovert>=1.0", + "sympy>=1.9", + "numpy>=1.23", + "dimod>=0.12.0", + "dwave-samplers==1.2", + "dwave-system>=1.20", "importlib_metadata>=3.6; python_version < '3.10'", "importlib_resources>=5.9; python_version < '3.10'", - "docplex", - "qiskit", - "qiskit_optimization", - "qiskit_ibm_provider", - "matplotlib", - "pandas", - "PyPortfolioOpt", - "scikit-learn" + "docplex>=2.22", + "qiskit==0.45.3", + "qiskit_optimization==0.4.0", + "qiskit_ibm_runtime==0.14.0", + "matplotlib>=3.8", + "pandas>=1.3", + "scikit-learn>=1.3" ] classifiers = [ From ce7c9165a7cce7ff2e0c41b6c54caf32ede1b178 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 27 May 2024 17:30:43 +0200 Subject: [PATCH 02/89] nox update --- src/mqt/qao/variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/qao/variables.py b/src/mqt/qao/variables.py index 99b524e..1bed1eb 100644 --- a/src/mqt/qao/variables.py +++ b/src/mqt/qao/variables.py @@ -920,7 +920,7 @@ def create(self, name: str, unipolar: bool = True) -> Symbol: class Discrete(Variable): - """child class of discrete variables""" + """child class of discrete variables """ def create(self, name: str, values: list[float]) -> Symbol: """function for creating the new discrete variable. From f30603eb42d36d6e772ae9078910918fd4e16743 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 27 May 2024 19:18:51 +0200 Subject: [PATCH 03/89] nox update --- src/mqt/qao/variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/qao/variables.py b/src/mqt/qao/variables.py index 1bed1eb..90b44e7 100644 --- a/src/mqt/qao/variables.py +++ b/src/mqt/qao/variables.py @@ -920,7 +920,7 @@ def create(self, name: str, unipolar: bool = True) -> Symbol: class Discrete(Variable): - """child class of discrete variables """ + """child class of discrete variables for representing variables that can assume a finite number of values""" def create(self, name: str, values: list[float]) -> Symbol: """function for creating the new discrete variable. From bf6b76f3e4b7a660e487dca846b3ca80c822ffba Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 27 May 2024 19:21:17 +0200 Subject: [PATCH 04/89] nox update --- noxfile.py | 1 + pyproject.toml | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/noxfile.py b/noxfile.py index d5aaee6..03a0d9d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -37,6 +37,7 @@ "pandas>=2.1", "qubovert>=1.0", "pandas>=1.3", +] if os.environ.get("CI", None): nox.options.error_on_missing_interpreters = True diff --git a/pyproject.toml b/pyproject.toml index 8f67744..42dcbac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,15 +19,22 @@ requires-python = ">=3.10,<3.12" dynamic = ["version"] dependencies = [ - "qubovert>=1.0", + "matplotlib>=3.8", + "numpy>=1.23", "sympy>=1.9", - "docplex>=2.22", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "matplotlib>=3.8", - "pandas>=1.3", - "scikit-learn>=1.3" + "pytest==7.4.0", + "scikit-learn>=1.3", + "dimod>=0.12.0", + "docplex>=2.22", + "dwave-preprocessing>=0.6.3 ", + "dwave-samplers==1.2", + "dwave-system>=1.20", + "pandas>=2.1", + "qubovert>=1.0", + "pandas>=1.3" ] classifiers = [ From d7374ae555f14c63f2b5d479d9ffd8bb8281d489 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 10:14:31 +0200 Subject: [PATCH 05/89] nox update --- .pre-commit-config.yaml | 23 +++++++++++------------ noxfile.py | 2 -- pyproject.toml | 2 -- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a0b456..6a408ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -87,23 +87,22 @@ repos: args: [] additional_dependencies: - importlib_resources - - qubovert - - pytest==7.4.0 - types-setuptools - setuptools<=65.6.3 - - sympy==1.12 - - numpy==1.23.5 - - dwave-samplers - - dwave.system - - docplex==2.25.236 + - matplotlib>=3.8 + - numpy>=1.23 + - sympy>=1.9 - qiskit==0.45.3 - qiskit_optimization==0.4.0 - - qiskit-algorithms==0.2.1 - qiskit_ibm_runtime==0.14.0 - - matplotlib - - pandas - - PyPortfolioOpt - - scikit-learn + - scikit-learn>=1.3 + - dimod>=0.12.0 + - docplex>=2.22 + - dwave-preprocessing>=0.6.3 + - dwave-samplers==1.2 + - dwave-system>=1.20 + - pandas>=2.1 + - qubovert>=1.0 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 03a0d9d..641a66d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -27,7 +27,6 @@ "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "pytest==7.4.0", "scikit-learn>=1.3", "dimod>=0.12.0", "docplex>=2.22", @@ -36,7 +35,6 @@ "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", - "pandas>=1.3", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 42dcbac..94f3199 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ dependencies = [ "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "pytest==7.4.0", "scikit-learn>=1.3", "dimod>=0.12.0", "docplex>=2.22", @@ -34,7 +33,6 @@ dependencies = [ "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", - "pandas>=1.3" ] classifiers = [ From 67ee83a9c65203256cdeedd3ffbdf190305a8b7e Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 10:22:03 +0200 Subject: [PATCH 06/89] nox update --- .pre-commit-config.yaml | 1 + noxfile.py | 1 + pyproject.toml | 1 + 3 files changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a408ad..34ee62b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -103,6 +103,7 @@ repos: - dwave-system>=1.20 - pandas>=2.1 - qubovert>=1.0 + - pytest>=7.4.0 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 641a66d..c178e8b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -35,6 +35,7 @@ "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", + "pytest>=7.4.0", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 94f3199..7371168 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ dependencies = [ "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", + "pytest>=7.4.0", ] classifiers = [ From 28e4a35703467ef4d8f143dfd85aaac7157253e2 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 12:32:13 +0200 Subject: [PATCH 07/89] nox update --- .pre-commit-config.yaml | 3 +-- noxfile.py | 3 +-- pyproject.toml | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 34ee62b..890ef24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -98,8 +98,7 @@ repos: - scikit-learn>=1.3 - dimod>=0.12.0 - docplex>=2.22 - - dwave-preprocessing>=0.6.3 - - dwave-samplers==1.2 + - dwave-samplers>=1.2 - dwave-system>=1.20 - pandas>=2.1 - qubovert>=1.0 diff --git a/noxfile.py b/noxfile.py index c178e8b..5200a7c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -30,8 +30,7 @@ "scikit-learn>=1.3", "dimod>=0.12.0", "docplex>=2.22", - "dwave-preprocessing>=0.6.3 ", - "dwave-samplers==1.2", + "dwave-samplers>=1.2", "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", diff --git a/pyproject.toml b/pyproject.toml index 7371168..5f9a129 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,7 @@ dependencies = [ "scikit-learn>=1.3", "dimod>=0.12.0", "docplex>=2.22", - "dwave-preprocessing>=0.6.3 ", - "dwave-samplers==1.2", + "dwave-samplers>=1.2", "dwave-system>=1.20", "pandas>=2.1", "qubovert>=1.0", From 76507a5fd84633cfd96d1e75f82caaa57f6c99e6 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 14:24:46 +0200 Subject: [PATCH 08/89] nox update --- .pre-commit-config.yaml | 23 ++++++++++++----------- noxfile.py | 23 ++++++++++++----------- pyproject.toml | 23 ++++++++++++----------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 890ef24..9aede45 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,20 +89,21 @@ repos: - importlib_resources - types-setuptools - setuptools<=65.6.3 - - matplotlib>=3.8 - - numpy>=1.23 - - sympy>=1.9 + - matplotlib==3.8 + - numpy==1.24 + - sympy==1.9 - qiskit==0.45.3 - qiskit_optimization==0.4.0 - qiskit_ibm_runtime==0.14.0 - - scikit-learn>=1.3 - - dimod>=0.12.0 - - docplex>=2.22 - - dwave-samplers>=1.2 - - dwave-system>=1.20 - - pandas>=2.1 - - qubovert>=1.0 - - pytest>=7.4.0 + - scikit-learn==1.3 + - dimod==0.12.14 + - docplex==2.25.236 + - dwave-preprocessing==0.6.5 + - dwave-samplers==1.2 + - dwave-system==1.24 + - pandas==2.1 + - qubovert==1.0 + - pytest==7.4.0 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 5200a7c..27e0f7f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -21,20 +21,21 @@ "setuptools>=66.1", "setuptools_scm>=7", "wheel>=0.40", - "matplotlib>=3.8", - "numpy>=1.23", - "sympy>=1.9", + "matplotlib==3.8", + "numpy==1.24", + "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn>=1.3", - "dimod>=0.12.0", - "docplex>=2.22", - "dwave-samplers>=1.2", - "dwave-system>=1.20", - "pandas>=2.1", - "qubovert>=1.0", - "pytest>=7.4.0", + "scikit-learn==1.3", + "dimod==0.12.14", + "docplex==2.25.236", + "dwave-preprocessing==0.6.5 ", + "dwave-samplers==1.2", + "dwave-system==1.24", + "pandas==2.1", + "qubovert==1.0", + "pytest==7.4.0", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 5f9a129..53dfaca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,20 +19,21 @@ requires-python = ">=3.10,<3.12" dynamic = ["version"] dependencies = [ - "matplotlib>=3.8", - "numpy>=1.23", - "sympy>=1.9", + "matplotlib==3.8", + "numpy==1.24", + "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn>=1.3", - "dimod>=0.12.0", - "docplex>=2.22", - "dwave-samplers>=1.2", - "dwave-system>=1.20", - "pandas>=2.1", - "qubovert>=1.0", - "pytest>=7.4.0", + "scikit-learn==1.3", + "dimod==0.12.14", + "docplex==2.25.236", + "dwave-preprocessing==0.6.5 ", + "dwave-samplers==1.2", + "dwave-system==1.24", + "pandas==2.1", + "qubovert==1.0", + "pytest==7.4.0", ] classifiers = [ From 0e9c53973678ce0944c01737055274759a093f4a Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 15:21:47 +0200 Subject: [PATCH 09/89] nox update --- .pre-commit-config.yaml | 23 +++++++++++------------ noxfile.py | 23 +++++++++++------------ pyproject.toml | 26 ++++++++++++++------------ 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9aede45..890ef24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,21 +89,20 @@ repos: - importlib_resources - types-setuptools - setuptools<=65.6.3 - - matplotlib==3.8 - - numpy==1.24 - - sympy==1.9 + - matplotlib>=3.8 + - numpy>=1.23 + - sympy>=1.9 - qiskit==0.45.3 - qiskit_optimization==0.4.0 - qiskit_ibm_runtime==0.14.0 - - scikit-learn==1.3 - - dimod==0.12.14 - - docplex==2.25.236 - - dwave-preprocessing==0.6.5 - - dwave-samplers==1.2 - - dwave-system==1.24 - - pandas==2.1 - - qubovert==1.0 - - pytest==7.4.0 + - scikit-learn>=1.3 + - dimod>=0.12.0 + - docplex>=2.22 + - dwave-samplers>=1.2 + - dwave-system>=1.20 + - pandas>=2.1 + - qubovert>=1.0 + - pytest>=7.4.0 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 27e0f7f..5200a7c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -21,21 +21,20 @@ "setuptools>=66.1", "setuptools_scm>=7", "wheel>=0.40", - "matplotlib==3.8", - "numpy==1.24", - "sympy==1.9", + "matplotlib>=3.8", + "numpy>=1.23", + "sympy>=1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn==1.3", - "dimod==0.12.14", - "docplex==2.25.236", - "dwave-preprocessing==0.6.5 ", - "dwave-samplers==1.2", - "dwave-system==1.24", - "pandas==2.1", - "qubovert==1.0", - "pytest==7.4.0", + "scikit-learn>=1.3", + "dimod>=0.12.0", + "docplex>=2.22", + "dwave-samplers>=1.2", + "dwave-system>=1.20", + "pandas>=2.1", + "qubovert>=1.0", + "pytest>=7.4.0", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 53dfaca..563d277 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,21 +19,23 @@ requires-python = ">=3.10,<3.12" dynamic = ["version"] dependencies = [ - "matplotlib==3.8", - "numpy==1.24", - "sympy==1.9", + "setuptools>=66.1", + "setuptools_scm>=7", + "wheel>=0.40", + "matplotlib>=3.8", + "numpy>=1.23", + "sympy>=1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn==1.3", - "dimod==0.12.14", - "docplex==2.25.236", - "dwave-preprocessing==0.6.5 ", - "dwave-samplers==1.2", - "dwave-system==1.24", - "pandas==2.1", - "qubovert==1.0", - "pytest==7.4.0", + "scikit-learn>=1.3", + "dimod>=0.12.0", + "docplex>=2.22", + "dwave-samplers>=1.2", + "dwave-system>=1.20", + "pandas>=2.1", + "qubovert>=1.0", + "pytest>=7.4.0", ] classifiers = [ From 7052f4b2082b809b0cf6977d12952d4ac8c9c3ca Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 16:07:16 +0200 Subject: [PATCH 10/89] nox update --- .pre-commit-config.yaml | 21 +++-- noxfile.py | 21 +++-- pyproject.toml | 21 +++-- src/mqt/qao/constraints.py | 134 +++++++++++++++---------------- src/mqt/qao/objectivefunction.py | 10 +-- src/mqt/qao/solvers.py | 2 +- src/mqt/qao/variables.py | 2 +- 7 files changed, 104 insertions(+), 107 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 890ef24..c4fdcc4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,20 +89,19 @@ repos: - importlib_resources - types-setuptools - setuptools<=65.6.3 - - matplotlib>=3.8 - - numpy>=1.23 - - sympy>=1.9 + - matplotlib==3.8 + - sympy==1.9 - qiskit==0.45.3 - qiskit_optimization==0.4.0 - qiskit_ibm_runtime==0.14.0 - - scikit-learn>=1.3 - - dimod>=0.12.0 - - docplex>=2.22 - - dwave-samplers>=1.2 - - dwave-system>=1.20 - - pandas>=2.1 - - qubovert>=1.0 - - pytest>=7.4.0 + - scikit-learn==1.3 + - dimod==0.12.14 + - docplex==2.22.213 + - dwave-samplers==1.2 + - dwave-system==1.20 + - pandas==2.1 + - qubovert==1.0 + - pytest==7.4.0 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 5200a7c..18600e6 100644 --- a/noxfile.py +++ b/noxfile.py @@ -21,20 +21,19 @@ "setuptools>=66.1", "setuptools_scm>=7", "wheel>=0.40", - "matplotlib>=3.8", - "numpy>=1.23", - "sympy>=1.9", + "matplotlib==3.8", + "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn>=1.3", - "dimod>=0.12.0", - "docplex>=2.22", - "dwave-samplers>=1.2", - "dwave-system>=1.20", - "pandas>=2.1", - "qubovert>=1.0", - "pytest>=7.4.0", + "scikit-learn==1.3", + "dimod==0.12.14", + "docplex==2.22.213", + "dwave-samplers==1.2", + "dwave-system==1.20", + "pandas==2.1", + "qubovert==1.0", + "pytest==7.4.0", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 563d277..176a0d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,20 +22,19 @@ dependencies = [ "setuptools>=66.1", "setuptools_scm>=7", "wheel>=0.40", - "matplotlib>=3.8", - "numpy>=1.23", - "sympy>=1.9", + "matplotlib==3.8", + "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", - "scikit-learn>=1.3", - "dimod>=0.12.0", - "docplex>=2.22", - "dwave-samplers>=1.2", - "dwave-system>=1.20", - "pandas>=2.1", - "qubovert>=1.0", - "pytest>=7.4.0", + "scikit-learn==1.3", + "dimod==0.12.14", + "docplex==2.22.213", + "dwave-samplers==1.2", + "dwave-system==1.20", + "pandas==2.1", + "qubovert==1.0", + "pytest==7.4.0", ] classifiers = [ diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index 85e2ab3..4cfaa51 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -204,11 +204,11 @@ def _not_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> print("Wrong constraint format\n") return False a = self._convert_expression_logic( - expand(cast(Expr, (el[0]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0]))).evalf(), var.binary_variables_name_weight, ) b = self._convert_expression_logic( - expand(cast(Expr, (el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[1]))).evalf(), var.binary_variables_name_weight, ) ret = 2 * a * b - a - b + 1 @@ -243,8 +243,8 @@ def _not_constraint_check(self, constraint: str, variables: Variables, solution: bool -- saying if the constraint is satisfied or not """ el = (constraint).replace("~", "").split("=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -307,8 +307,8 @@ def _not_constraint_check_no_sub(self, constraint: str, solution: dict[str, int] bool -- saying if the constraint is satisfied or not """ el = (constraint).replace("~", "").split("=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -360,15 +360,15 @@ def _and_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> print("Wrong constraint format\n") return False a = self._convert_expression_logic( - expand(cast(Expr, (el2[0]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el2[0]))).evalf(), var.binary_variables_name_weight, ) b = self._convert_expression_logic( - expand(cast(Expr, (el2[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el2[1]))).evalf(), var.binary_variables_name_weight, ) c = self._convert_expression_logic( - expand(cast(Expr, (el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[1]))).evalf(), var.binary_variables_name_weight, ) ret = a * b - 2 * (a + b) * c + 3 * c @@ -415,9 +415,9 @@ def _and_constraint_check(self, constraint: str, variables: Variables, solution: if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) expr3_to_sub = bool(not str(expr3).replace(".", "").isnumeric()) @@ -504,9 +504,9 @@ def _and_constraint_check_no_sub(self, constraint: str, solution: dict[str, int] if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -565,15 +565,15 @@ def _or_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> print("Wrong constraint format\n") return False a = self._convert_expression_logic( - expand(cast(Expr, (el2[0]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el2[0]))).evalf(), var.binary_variables_name_weight, ) b = self._convert_expression_logic( - expand(cast(Expr, (el2[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el2[1]))).evalf(), var.binary_variables_name_weight, ) c = self._convert_expression_logic( - expand(cast(Expr, (el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[1]))).evalf(), var.binary_variables_name_weight, ) ret = a * b + (a + b) * (1 - 2 * c) + c @@ -619,9 +619,9 @@ def _or_constraint_check(self, constraint: str, variables: Variables, solution: if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) expr3_to_sub = bool(not str(expr3).replace(".", "").isnumeric()) @@ -708,9 +708,9 @@ def _or_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -767,9 +767,9 @@ def _xor_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> if len(el2) != 2: print("Wrong constraint format\n") return False - a = self._convert_expression_logic(expand(cast(Expr, (el2[0]))).evalf(), var.binary_variables_name_weight) # type: ignore[no-untyped-call] - b = self._convert_expression_logic(expand(cast(Expr, (el2[1]))).evalf(), var.binary_variables_name_weight) # type: ignore[no-untyped-call] - c = self._convert_expression_logic(expand(cast(Expr, (el[1]))).evalf(), var.binary_variables_name_weight) # type: ignore[no-untyped-call] + a = self._convert_expression_logic(expand(cast(Expr, (el2[0]))).evalf(), var.binary_variables_name_weight) + b = self._convert_expression_logic(expand(cast(Expr, (el2[1]))).evalf(), var.binary_variables_name_weight) + c = self._convert_expression_logic(expand(cast(Expr, (el[1]))).evalf(), var.binary_variables_name_weight) ret = a + b + c - 2 * a * c - 2 * b * c - 2 * a * b + 4 * a * b * c else: el = str(elem[0]).replace(" ", "").split("=") @@ -815,9 +815,9 @@ def _xor_constraint_check(self, constraint: str, variables: Variables, solution: if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) expr3_to_sub = bool(not str(expr3).replace(".", "").isnumeric()) @@ -904,9 +904,9 @@ def _xor_constraint_check_no_sub(self, constraint: str, solution: dict[str, int] if len(el2) != 2: print("Wrong constraint format\n") return False - expr1 = expand(cast(Expr, (el2[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el2[1]))).evalf() # type: ignore[no-untyped-call] - expr3 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el2[0]))).evalf() + expr2 = expand(cast(Expr, (el2[1]))).evalf() + expr3 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -975,7 +975,7 @@ def _greq_constraint( exp = PUBO() if elem[3]: ret_func = self._convert_expression_prec( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, var.variables_dict, ) @@ -984,7 +984,7 @@ def _greq_constraint( var_precision = ret_func[1] else: exp = self._convert_expression( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) @@ -1010,7 +1010,7 @@ def _greq_constraint( ret = (exp) ** 2, i, j, aux else: el = str(elem[0]).split(">=") - exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() # type: ignore[no-untyped-call] + exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: @@ -1048,8 +1048,8 @@ def _greq_constraint_check(self, constraint: str, variables: Variables, solution bool -- saying if the constraint is satisfied or not """ el = constraint.split(">=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -1112,8 +1112,8 @@ def _greq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int bool -- saying if the constraint is satisfied or not """ el = (constraint).split(">=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -1174,7 +1174,7 @@ def _lteq_constraint( exp = PUBO() if elem[3]: ret_func = self._convert_expression_prec( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, var.variables_dict, ) @@ -1183,7 +1183,7 @@ def _lteq_constraint( var_precision = ret_func[1] else: exp = self._convert_expression( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) min_val, max_val, const = self._min_max_const_estimation(exp) @@ -1209,7 +1209,7 @@ def _lteq_constraint( ret = (exp) ** 2, i, j, aux else: el = str(elem[0]).split("<=") - exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() # type: ignore[no-untyped-call] + exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() min_val, max_val, const = self._min_max_const_estimation(exp) const = -const if const - min_val > 0: @@ -1247,8 +1247,8 @@ def _lteq_constraint_check(self, constraint: str, variables: Variables, solution bool -- saying if the constraint is satisfied or not """ el = constraint.split("<=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -1311,8 +1311,8 @@ def _lteq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int bool -- saying if the constraint is satisfied or not """ el = (constraint).split("<=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -1373,7 +1373,7 @@ def _grt_constraint( exp = PUBO() if elem[3]: ret_func = self._convert_expression_prec( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, var.variables_dict, ) @@ -1382,7 +1382,7 @@ def _grt_constraint( var_precision = ret_func[1] else: exp = self._convert_expression( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) min_val, max_val, const = self._min_max_const_estimation(exp) @@ -1410,7 +1410,7 @@ def _grt_constraint( ret = (exp) ** 2, i, j, aux else: el = str(elem[0]).split(">") - exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() # type: ignore[no-untyped-call] + exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: @@ -1456,8 +1456,8 @@ def _grt_constraint_check(self, constraint: str, variables: Variables, solution: bool -- saying if the constraint is satisfied or not """ el = constraint.split(">") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -1520,8 +1520,8 @@ def _grt_constraint_check_no_sub(self, constraint: str, solution: dict[str, int] bool -- saying if the constraint is satisfied or not """ el = (constraint).split(">") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -1582,7 +1582,7 @@ def _lt_constraint( exp = PUBO() if elem[3]: ret_func = self._convert_expression_prec( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, var.variables_dict, ) @@ -1591,7 +1591,7 @@ def _lt_constraint( var_precision = ret_func[1] else: exp = self._convert_expression( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) min_val, max_val, const = self._min_max_const_estimation(exp) @@ -1622,7 +1622,7 @@ def _lt_constraint( ret = (exp) ** 2, i, j, aux else: el = str(elem[0]).split("<") - exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() # type: ignore[no-untyped-call] + exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() min_val, max_val, const = self._min_max_const_estimation(exp) const = -const if const - min_val > 0: @@ -1669,8 +1669,8 @@ def _lt_constraint_check(self, constraint: str, variables: Variables, solution: bool -- saying if the constraint is satisfied or not """ el = constraint.split("<") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -1733,8 +1733,8 @@ def _lt_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) bool -- saying if the constraint is satisfied or not """ el = (constraint).split("<") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols @@ -1779,13 +1779,13 @@ def _eq_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> if elem[2]: el = str(elem[0]).split("=") exp = self._convert_expression( - expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), # type: ignore[no-untyped-call] + expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) ret = (exp) ** 2 else: el = str(elem[0]).split("=") - exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() # type: ignore[no-untyped-call] + exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() hamiltonian = self._expression_to_hamiltonian( cast(Expr, exp), list(var.binary_variables_name_weight.values()) ) @@ -1804,8 +1804,8 @@ def _eq_constraint_check(self, constraint: str, variables: Variables, solution: bool -- saying if the constraint is satisfied or not """ el = constraint.split("=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = bool(not str(expr1).replace(".", "").isnumeric()) expr2_to_sub = bool(not str(expr2).replace(".", "").isnumeric()) if expr2_to_sub or expr1_to_sub: @@ -1868,8 +1868,8 @@ def _eq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) bool -- saying if the constraint is satisfied or not """ el = (constraint).split("=") - expr1 = expand(cast(Expr, (el[0]))).evalf() # type: ignore[no-untyped-call] - expr2 = expand(cast(Expr, (el[1]))).evalf() # type: ignore[no-untyped-call] + expr1 = expand(cast(Expr, (el[0]))).evalf() + expr2 = expand(cast(Expr, (el[1]))).evalf() expr1_to_sub = True if not str(expr1).replace(".", "").isnumeric(): symbols_in_the_expression1 = expr1.free_symbols diff --git a/src/mqt/qao/objectivefunction.py b/src/mqt/qao/objectivefunction.py index dcac1e9..3ae4c74 100644 --- a/src/mqt/qao/objectivefunction.py +++ b/src/mqt/qao/objectivefunction.py @@ -32,7 +32,7 @@ def add_objective_function(self, objective_function: Expr, minimization: bool = """ if not minimization: objective_function = -objective_function - self.objective_functions.append((cast(Expr, expand(objective_function).evalf()), weight)) # type: ignore[no-untyped-call] + self.objective_functions.append((cast(Expr, expand(objective_function).evalf()), weight)) def rewrite_cost_functions(self, pubo: PUBO, var: Variables) -> PUBO | bool: """function for rewriting the cost functions according with the variable structure @@ -167,22 +167,22 @@ def substitute_values(self, solution: dict[str, Any], variables: Variables) -> d for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - temp_expression = temp_expression.subs({variables.variables_dict[var].symbol: solution[var]}) # type: ignore[no-untyped-call] + temp_expression = temp_expression.subs({variables.variables_dict[var].symbol: solution[var]}) elif isinstance(solution[var], list): for i in range(len(solution[var])): if isinstance(solution[var][i], list): for j in range(len(solution[var][i])): if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): - temp_expression = temp_expression.subs( # type: ignore[no-untyped-call] + temp_expression = temp_expression.subs( {variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][k]} ) else: - temp_expression = temp_expression.subs( # type: ignore[no-untyped-call] + temp_expression = temp_expression.subs( {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} ) else: - temp_expression = temp_expression.subs( # type: ignore[no-untyped-call] + temp_expression = temp_expression.subs( {variables.variables_dict[var][i].symbol: solution[var][i]} ) try: diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index d9f20c9..c925fa2 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -1208,7 +1208,7 @@ def show_cumulative( plt.close() else: if show: - plt.show() + plt.show() # type: ignore[no-untyped-call] def valid_solutions(self, weak: bool = True) -> float: """function for evaluating the rate of valid solution and the amount of violations diff --git a/src/mqt/qao/variables.py b/src/mqt/qao/variables.py index 90b44e7..daa7025 100644 --- a/src/mqt/qao/variables.py +++ b/src/mqt/qao/variables.py @@ -669,7 +669,7 @@ def _dictionary_encoding( i += 1 # Add the needed constraint - constraints.append((format(expand(var_sum).evalf()) + " = 1", True, False, False)) # type: ignore[no-untyped-call] + constraints.append((format(expand(var_sum).evalf()) + " = 1", True, False, False)) return binary_variables_name_weight, constraints, i def _unitary_encoding( From 5ec191783a1518cec261ccb8591d6a42e5fac933 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 18:55:08 +0200 Subject: [PATCH 11/89] nox update --- .pre-commit-config.yaml | 4 ++-- noxfile.py | 8 ++++---- pyproject.toml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c4fdcc4..de0200e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -88,14 +88,14 @@ repos: additional_dependencies: - importlib_resources - types-setuptools - - setuptools<=65.6.3 + - setuptools==66.1.0 - matplotlib==3.8 - sympy==1.9 - qiskit==0.45.3 - qiskit_optimization==0.4.0 - qiskit_ibm_runtime==0.14.0 - scikit-learn==1.3 - - dimod==0.12.14 + - dimod==0.12.7 - docplex==2.22.213 - dwave-samplers==1.2 - dwave-system==1.20 diff --git a/noxfile.py b/noxfile.py index 18600e6..75f33f0 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,16 +18,16 @@ PYTHON_ALL_VERSIONS = ["3.10", "3.11"] BUILD_REQUIREMENTS = [ - "setuptools>=66.1", - "setuptools_scm>=7", - "wheel>=0.40", + "setuptools==66.1.0", + "setuptools_scm==7.0.1", + "wheel==0.40", "matplotlib==3.8", "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", "scikit-learn==1.3", - "dimod==0.12.14", + "dimod==0.12.7", "docplex==2.22.213", "dwave-samplers==1.2", "dwave-system==1.20", diff --git a/pyproject.toml b/pyproject.toml index 176a0d7..aca3e05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,16 +19,16 @@ requires-python = ">=3.10,<3.12" dynamic = ["version"] dependencies = [ - "setuptools>=66.1", - "setuptools_scm>=7", - "wheel>=0.40", + "setuptools==66.1.0", + "setuptools_scm==7.0.1", + "wheel==0.40", "matplotlib==3.8", "sympy==1.9", "qiskit==0.45.3", "qiskit_optimization==0.4.0", "qiskit_ibm_runtime==0.14.0", "scikit-learn==1.3", - "dimod==0.12.14", + "dimod==0.12.7", "docplex==2.22.213", "dwave-samplers==1.2", "dwave-system==1.20", From f17b56afc77973404871cb44ff7d9f2e6bc764d5 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 19:01:37 +0200 Subject: [PATCH 12/89] nox update --- .pre-commit-config.yaml | 1 + noxfile.py | 1 + pyproject.toml | 1 + 3 files changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de0200e..948a110 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -102,6 +102,7 @@ repos: - pandas==2.1 - qubovert==1.0 - pytest==7.4.0 + - tomli==2.0.1 # Catch common capitalization mistakes - repo: local diff --git a/noxfile.py b/noxfile.py index 75f33f0..f35e6d6 100644 --- a/noxfile.py +++ b/noxfile.py @@ -34,6 +34,7 @@ "pandas==2.1", "qubovert==1.0", "pytest==7.4.0", + "tomli==2.0.1", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index aca3e05..0734042 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ "pandas==2.1", "qubovert==1.0", "pytest==7.4.0", + "tomli==2.0.1" ] classifiers = [ From 783c51708080cf99521ecdb25c11927c06bd9aed Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Tue, 28 May 2024 19:13:24 +0200 Subject: [PATCH 13/89] nox update --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 948a110..de0200e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -102,7 +102,6 @@ repos: - pandas==2.1 - qubovert==1.0 - pytest==7.4.0 - - tomli==2.0.1 # Catch common capitalization mistakes - repo: local From 1c0ca4f767750649c13280460075d861d09312c2 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 12:15:56 +0200 Subject: [PATCH 14/89] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20updated=20pre-commit?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 88 +++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de0200e..79667a1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,22 +15,35 @@ ci: repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.5.0" + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-case-conflict - id: check-docstring-first - id: check-merge-conflict + - id: check-symlinks - id: check-toml - id: check-yaml - id: debug-statements - id: end-of-file-fixer - id: mixed-line-ending + - id: requirements-txt-fixer - id: trailing-whitespace + # Clean jupyter notebooks + - repo: https://github.com/srstevenson/nb-clean + rev: 3.2.0 + hooks: + - id: nb-clean + args: + - --remove-empty-cells + - --preserve-cell-metadata + - raw_mimetype + - -- + # Handling unwanted unicode characters - repo: https://github.com/sirosen/texthooks - rev: "0.6.2" + rev: 0.6.6 hooks: - id: fix-ligatures - id: fix-smartquotes @@ -43,28 +56,9 @@ repos: - id: rst-directive-colons - id: rst-inline-touching-normal - # Clean jupyter notebooks - - repo: https://github.com/srstevenson/nb-clean - rev: "3.1.0" - hooks: - - id: nb-clean - # Check for spelling - - repo: https://github.com/codespell-project/codespell - rev: "v2.2.6" - hooks: - - id: codespell - args: ["-L", "wille,linz,fro"] - exclude: "mqt/benchviewer/templates/legal.html" - - # Format configuration files with prettier - - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v3.0.3" - hooks: - - id: prettier - types_or: [yaml, markdown, html, css, javascript, json] - + # Python linting using ruff - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.4 + rev: v0.4.5 hooks: - id: ruff args: ["--fix", "--show-fixes"] @@ -72,36 +66,36 @@ repos: - id: ruff-format types_or: [python, pyi, jupyter] + # Static type checking using mypy + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.10.0 + hooks: + - id: mypy + files: ^(src/mqt|tests) + args: [] + additional_dependencies: + - pytest + # Also run Black on examples in the documentation - repo: https://github.com/adamchainz/blacken-docs rev: 1.16.0 hooks: - id: blacken-docs - additional_dependencies: [black==23.*] + additional_dependencies: [black==24.*] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + # Format configuration files with prettier + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 hooks: - - id: mypy - files: ^(src|tests) - args: [] - additional_dependencies: - - importlib_resources - - types-setuptools - - setuptools==66.1.0 - - matplotlib==3.8 - - sympy==1.9 - - qiskit==0.45.3 - - qiskit_optimization==0.4.0 - - qiskit_ibm_runtime==0.14.0 - - scikit-learn==1.3 - - dimod==0.12.7 - - docplex==2.22.213 - - dwave-samplers==1.2 - - dwave-system==1.20 - - pandas==2.1 - - qubovert==1.0 - - pytest==7.4.0 + - id: prettier + types_or: [yaml, markdown, html, css, scss, javascript, json] + + # Check for spelling + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: ["-L", "wille,linz", "--skip", "*.ipynb"] # Catch common capitalization mistakes - repo: local @@ -110,7 +104,7 @@ repos: name: Disallow improper capitalization language: pygrep entry: PyBind|Numpy|Cmake|CCache|Github|PyTest|Mqt|Tum - exclude: (.joblib|.pre-commit-config.yaml) + exclude: .pre-commit-config.yaml # Check best practices for scientific Python code - repo: https://github.com/scientific-python/cookie From 1f25525bc0b9c584cd1cbf54293cfb2066f201dc Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 12:16:13 +0200 Subject: [PATCH 15/89] =?UTF-8?q?=F0=9F=94=A5=20remove=20useless=20config?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flake8 | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 5b92ae3..0000000 --- a/.flake8 +++ /dev/null @@ -1,18 +0,0 @@ -[flake8] -extend-select = B9 -extend-ignore = E203, E231, E501, E722, W503, B950, B014, W504, E123, E126, E226, E121, B905, SIM113 -per-file-ignores = __init__.py:F401 -max-line-length = 120 -show-source = true -exclude = - .git, - .idea, - .eggs, - __pycache__, - .tox, - docs/source/conf.py, - build, - .nox, - venv, - .venv -application-import-names = mqt.qao From 35f5f249ade4cc89a28308d40d2648ceedfd886d Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 12:17:23 +0200 Subject: [PATCH 16/89] =?UTF-8?q?=F0=9F=9A=A8=20apply=20auto-fixes=20from?= =?UTF-8?q?=20ruff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/qao/__init__.py | 6 +- src/mqt/qao/constraints.py | 444 ++++++++++++++----------------- src/mqt/qao/objectivefunction.py | 22 +- src/mqt/qao/solvers.py | 74 ++---- src/mqt/qao/variables.py | 242 +++++++++-------- tests/test_evaluation.py | 30 +-- 6 files changed, 368 insertions(+), 450 deletions(-) diff --git a/src/mqt/qao/__init__.py b/src/mqt/qao/__init__.py index 3077977..e3f5615 100644 --- a/src/mqt/qao/__init__.py +++ b/src/mqt/qao/__init__.py @@ -2,20 +2,20 @@ import logging -from mqt.qao.variables import Variable, Variables from mqt.qao.constraints import Constraints from mqt.qao.objectivefunction import ObjectiveFunction from mqt.qao.problem import Problem from mqt.qao.solvers import Solution, Solver +from mqt.qao.variables import Variable, Variables __all__ = [ - "Variable", - "Variables", "Constraints", "ObjectiveFunction", "Problem", "Solution", "Solver", + "Variable", + "Variables", ] logger = logging.getLogger("mqt-qao") diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index 4cfaa51..f2b7346 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -262,30 +262,26 @@ def _not_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -438,42 +434,36 @@ def _and_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr3_to_sub: - expr3 = expr3.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr3_to_sub: - expr3 = expr3.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -642,42 +632,36 @@ def _or_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr3_to_sub: - expr3 = expr3.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr3_to_sub: - expr3 = expr3.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -838,42 +822,36 @@ def _xor_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr3_to_sub: - expr3 = expr3.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr3_to_sub: - expr3 = expr3.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr3 = expr3.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -988,7 +966,7 @@ def _greq_constraint( var.binary_variables_name_weight, ) - min_val, max_val, const = self._min_max_const_estimation(exp) + _min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: if elem[3] and float("0." + str(max_val + const).split(".")[1]) != 0.0: @@ -1011,7 +989,7 @@ def _greq_constraint( else: el = str(elem[0]).split(">=") exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() - min_val, max_val, const = self._min_max_const_estimation(exp) + _min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: precision = float("0." + str(max_val + const).split(".")[1]) @@ -1067,30 +1045,26 @@ def _greq_constraint_check(self, constraint: str, variables: Variables, solution if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -1186,7 +1160,7 @@ def _lteq_constraint( expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) - min_val, max_val, const = self._min_max_const_estimation(exp) + min_val, _max_val, const = self._min_max_const_estimation(exp) const = -const if const - min_val > 0: if len(str(const - min_val).split(".")) == 2: @@ -1210,7 +1184,7 @@ def _lteq_constraint( else: el = str(elem[0]).split("<=") exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() - min_val, max_val, const = self._min_max_const_estimation(exp) + min_val, _max_val, const = self._min_max_const_estimation(exp) const = -const if const - min_val > 0: if len(str(const - min_val).split(".")) == 2: @@ -1266,30 +1240,26 @@ def _lteq_constraint_check(self, constraint: str, variables: Variables, solution if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -1385,7 +1355,7 @@ def _grt_constraint( expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) - min_val, max_val, const = self._min_max_const_estimation(exp) + _min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: if elem[3] and float("0." + str(max_val + const).split(".")[1]) != 0.0: @@ -1411,7 +1381,7 @@ def _grt_constraint( else: el = str(elem[0]).split(">") exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() - min_val, max_val, const = self._min_max_const_estimation(exp) + _min_val, max_val, const = self._min_max_const_estimation(exp) if max_val + const > 0: if len(str(max_val + const).split(".")) == 2: precision = float("0." + str(max_val + const).split(".")[1]) @@ -1475,30 +1445,26 @@ def _grt_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -1594,7 +1560,7 @@ def _lt_constraint( expand(cast(Expr, (el[0] + "-" + el[1]))).evalf(), var.binary_variables_name_weight, ) - min_val, max_val, const = self._min_max_const_estimation(exp) + min_val, _max_val, const = self._min_max_const_estimation(exp) precision = 1.0 const = -const if const - min_val > 0: @@ -1607,9 +1573,8 @@ def _lt_constraint( precision = float("0." + str(const - min_val).split(".")[1]) if precision == 0.0: precision = 1 - else: - if elem[3]: - precision = min(1, var_precision) + elif elem[3]: + precision = min(1, var_precision) if precision != const - min_val: aux_var = aux.add_continuous_variable("aux" + format(j), precision, const - min_val, precision) j += 1 @@ -1623,7 +1588,7 @@ def _lt_constraint( else: el = str(elem[0]).split("<") exp = expand(cast(Expr, (el[0] + "-" + el[1]))).evalf() - min_val, max_val, const = self._min_max_const_estimation(exp) + min_val, _max_val, const = self._min_max_const_estimation(exp) const = -const if const - min_val > 0: if len(str(const - min_val).split(".")) == 2: @@ -1688,30 +1653,26 @@ def _lt_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -1823,30 +1784,26 @@ def _eq_constraint_check(self, constraint: str, variables: Variables, solution: if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): if expr1_to_sub: - expr1 = expr1.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) if expr2_to_sub: - expr2 = expr2.subs( - { - variables.variables_dict[var][i][j][k].symbol: solution[var][i][ - j - ][k] - } - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ + k + ] + }) else: if expr1_to_sub: - expr1 = expr1.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr1 = expr1.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) if expr2_to_sub: - expr2 = expr2.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + expr2 = expr2.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: if expr1_to_sub: expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) @@ -1911,7 +1868,7 @@ def _convert_expression(self, expr: Expr, binary_variables_name_weight: dict[str func = PUBO() sign = "+" for field in fields: - if field != "+" and field != "-": + if field not in {"+", "-"}: poly_fields = field.split("*") to_add = 1.0 for poly_field in poly_fields: @@ -1949,7 +1906,7 @@ def _convert_expression(self, expr: Expr, binary_variables_name_weight: dict[str elif len(elem) == 3: t = t * elem[1] + elem[2] temp += t - temp = temp**power + temp **= power else: t = 1.0 t *= binary_variables_name_weight[key][0] @@ -2015,7 +1972,7 @@ def _convert_expression_prec( sign = "+" min_precision = 1 for field in fields: - if field != "+" and field != "-": + if field not in {"+", "-"}: poly_fields = field.split("*") to_add = 1.0 for poly_field in poly_fields: @@ -2053,7 +2010,7 @@ def _convert_expression_prec( elif len(elem) == 3: t = t * elem[1] + elem[2] temp += t - temp = temp**power + temp **= power else: t = 1.0 t *= binary_variables_name_weight[key][0] @@ -2078,8 +2035,7 @@ def _convert_expression_prec( and name[0] in variables_dict and variables_dict[name[0]][int(name[1])].type == "c" ): - if min_precision > variables_dict[name[0]][int(name[1])].precision: - min_precision = variables_dict[name[0]][int(name[1])].precision + min_precision = min(min_precision, variables_dict[name[0]][int(name[1])].precision) elif ( len(name) == 3 and name[1].isnumeric() @@ -2087,8 +2043,9 @@ def _convert_expression_prec( and name[0] in variables_dict and variables_dict[name[0]][int(name[1])][int(name[2])].type == "c" ): - if min_precision > variables_dict[name[0]][int(name[1])][int(name[2])].precision: - min_precision = variables_dict[name[0]][int(name[1])][int(name[2])].precision + min_precision = min( + min_precision, variables_dict[name[0]][int(name[1])][int(name[2])].precision + ) elif ( len(name) == 4 and name[1].isnumeric() @@ -2136,8 +2093,7 @@ def _convert_expression_prec( to_add *= temp name = key.split("_") if len(name) == 1 and variables_dict[name[0]].type == "c": - if min_precision > variables_dict[name[0]].precision: - min_precision = variables_dict[name[0]].precision + min_precision = min(min_precision, variables_dict[name[0]].precision) elif ( len(name) == 2 and name[1].isnumeric() @@ -2165,20 +2121,16 @@ def _convert_expression_prec( and name[0] in variables_dict and variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].type == "c" ): - if ( - min_precision - > variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision - ): - min_precision = variables_dict[name[0]][int(name[1])][int(name[2])][ - int(name[3]) - ].precision - else: - if ( - name is variables_dict.keys() - and variables_dict[name[0]].type == "c" - and min_precision > variables_dict[name[0]].precision - ): - min_precision = variables_dict[name[0]].precision + min_precision = min( + min_precision, + variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision, + ) + elif ( + name is variables_dict.keys() + and variables_dict[name[0]].type == "c" + and min_precision > variables_dict[name[0]].precision + ): + min_precision = variables_dict[name[0]].precision if sign == "+": func += to_add @@ -2248,7 +2200,7 @@ def _expression_to_hamiltonian(self, exp: Expr, binary_variables_name_weight_val hamiltonian = PUBO() sign = "+" for field in fields: - if field != "+" and field != "-": + if field not in {"+", "-"}: poly_fields = field.split("*") to_add = 1.0 for poly_field in poly_fields: diff --git a/src/mqt/qao/objectivefunction.py b/src/mqt/qao/objectivefunction.py index 3ae4c74..e4ad8bf 100644 --- a/src/mqt/qao/objectivefunction.py +++ b/src/mqt/qao/objectivefunction.py @@ -53,7 +53,7 @@ def rewrite_cost_functions(self, pubo: PUBO, var: Variables) -> PUBO | bool: func = 0.0 sign = "+" for field in fields: - if field != "+" and field != "-": + if field not in {"+", "-"}: poly_fields = field.split("*") to_add = 1.0 for poly_field in poly_fields: @@ -91,7 +91,7 @@ def rewrite_cost_functions(self, pubo: PUBO, var: Variables) -> PUBO | bool: elif len(elem) == 3: t = t * elem[1] + elem[2] temp += t - temp = temp**power + temp **= power elif isinstance(var.binary_variables_name_weight[key], tuple): t = 1.0 t *= var.binary_variables_name_weight[key][0] @@ -174,17 +174,17 @@ def substitute_values(self, solution: dict[str, Any], variables: Variables) -> d for j in range(len(solution[var][i])): if isinstance(solution[var][i][j], list): for k in range(len(solution[var][i][j])): - temp_expression = temp_expression.subs( - {variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][k]} - ) + temp_expression = temp_expression.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][k] + }) else: - temp_expression = temp_expression.subs( - {variables.variables_dict[var][i][j].symbol: solution[var][i][j]} - ) + temp_expression = temp_expression.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) else: - temp_expression = temp_expression.subs( - {variables.variables_dict[var][i].symbol: solution[var][i]} - ) + temp_expression = temp_expression.subs({ + variables.variables_dict[var][i].symbol: solution[var][i] + }) try: objective_functions_values[str(obj[0])] = float(temp_expression) except ValueError: diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index c925fa2..e8f40fa 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -3,7 +3,7 @@ import json import logging -from math import ceil, log, sqrt +from math import ceil, log, log2, sqrt from pathlib import Path from time import time_ns from typing import TYPE_CHECKING, Any @@ -15,22 +15,23 @@ from dwave.system import DWaveSampler, EmbeddingComposite from matplotlib import rc from qiskit.algorithms import QAOA, VQE -from qiskit.circuit import QuantumCircuit, Parameter +from qiskit.circuit import Parameter, QuantumCircuit from qiskit.circuit.library import TwoLocal from qiskit.exceptions import QiskitError +from qiskit.providers.basicaer import BasicAer +from qiskit_ibm_runtime import QiskitRuntimeService # type: ignore[import-untyped] from qiskit_optimization.algorithms import ( GroverOptimizer, MinimumEigenOptimizationResult, MinimumEigenOptimizer, OptimizationResult, ) -from qiskit_ibm_runtime import QiskitRuntimeService # type: ignore[import-untyped] from qiskit_optimization.translators import from_docplex_mp -from qiskit.providers.basicaer import BasicAer from qubovert import PUBO, QUBO if TYPE_CHECKING: from collections.abc import Callable + from dimod import SampleSet from qiskit.algorithms.optimizers import Optimizer from qiskit.opflow import ( @@ -448,27 +449,11 @@ def solve_grover_adaptive_search_qubo( if auto_setting: # To change with the experience # num_runs = 100 threshold = 2 * len(self.qubo.variables) - qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)), - 2, - ) - ) - else: - if boundaries_estimation_method == "upper lower bound posiform and negaform method": - qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)), - 2, - ) - ) - elif boundaries_estimation_method == "naive": - qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)), - 2, - ) - ) + qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)))) + elif boundaries_estimation_method == "upper lower bound posiform and negaform method": + qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)))) + elif boundaries_estimation_method == "naive": + qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)))) if simulator: try: # Load your IBM Quantum account @@ -523,28 +508,12 @@ def solve_grover_adaptive_search_qubo( scaled_qubo = round(scaled_qubo_c / min_coeff) qp = self._from_qubovert_to_qiskit_model(scaled_qubo) - if auto_setting: + if auto_setting or boundaries_estimation_method == "upper lower bound posiform and negaform method": qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)), - 2, - ) + log2(abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo))) ) - else: - if boundaries_estimation_method == "upper lower bound posiform and negaform method": - qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_posiform_and_negaform_method(scaled_qubo)), - 2, - ) - ) - elif boundaries_estimation_method == "naive": - qubit_values = ceil( - log( - abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)), - 2, - ) - ) + elif boundaries_estimation_method == "naive": + qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)))) grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, quantum_instance=backend) @@ -1168,7 +1137,7 @@ def show_cumulative( rc("text", usetex=True) plt.rc("text", usetex=True) if label: - n, bins, patches = plt.hist( + _n, _bins, _patches = plt.hist( self.energies, cumulative=True, histtype="step", @@ -1177,17 +1146,17 @@ def show_cumulative( label=r"\textit{" + label + "}", ) else: - n, bins, patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) + _n, _bins, _patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) plt.title(r"\textbf{Cumulative distribution}", fontsize=20) plt.xlabel(r"\textit{Energy}", fontsize=20) plt.ylabel(r"\textit{occurrence}", fontsize=20) else: if label: - n, bins, patches = plt.hist( + _n, _bins, _patches = plt.hist( self.energies, cumulative=True, histtype="step", linewidth=2, bins=100, label=label ) else: - n, bins, patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) + _n, _bins, _patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) plt.title("Cumulative distribution", fontsize=20) plt.xlabel("Energy", fontsize=20) plt.ylabel("occurrence", fontsize=20) @@ -1206,9 +1175,8 @@ def show_cumulative( plt.savefig(filename + ".png", format="png") plt.savefig(filename + ".pdf", format="pdf") plt.close() - else: - if show: - plt.show() # type: ignore[no-untyped-call] + elif show: + plt.show() # type: ignore[no-untyped-call] def valid_solutions(self, weak: bool = True) -> float: """function for evaluating the rate of valid solution and the amount of violations @@ -1236,7 +1204,7 @@ def valid_solutions(self, weak: bool = True) -> float: else: self.valid_solution_rate[count] = 1 for key in self.valid_solution_rate: - self.valid_solution_rate[key] = self.valid_solution_rate[key] / len(all_satisfied) + self.valid_solution_rate[key] /= len(all_satisfied) return self.valid_solution_rate[0] def p_range(self, ref_value: float | None = None) -> float: diff --git a/src/mqt/qao/variables.py b/src/mqt/qao/variables.py index daa7025..e89290a 100644 --- a/src/mqt/qao/variables.py +++ b/src/mqt/qao/variables.py @@ -3,7 +3,7 @@ # numpy for matrix management from __future__ import annotations -from math import ceil, floor, log, sqrt +from math import ceil, floor, log, log2, sqrt from typing import Any import numpy as np @@ -512,21 +512,20 @@ def convert_simulated_annealing_solution(self, solution: dict[str, float]) -> di if next(iter(el[0].variables)) not in solution: print("The variable is not found\n") return False + elif next(iter(self.binary_variables_name_weight[v.name][0].variables)) in solution: + if ( + solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 + ) and len(self.binary_variables_name_weight[v.name]) > 1: + temp += self.binary_variables_name_weight[v.name][1] + if ( + solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 + ) and len(self.binary_variables_name_weight[v.name]) == 1: + temp += 1 + if len(self.binary_variables_name_weight[v.name]) == 3: + temp += self.binary_variables_name_weight[v.name][2] else: - if next(iter(self.binary_variables_name_weight[v.name][0].variables)) in solution: - if ( - solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 - ) and len(self.binary_variables_name_weight[v.name]) > 1: - temp += self.binary_variables_name_weight[v.name][1] - if ( - solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 - ) and len(self.binary_variables_name_weight[v.name]) == 1: - temp += 1 - if len(self.binary_variables_name_weight[v.name]) == 3: - temp += self.binary_variables_name_weight[v.name][2] - else: - print("The variable is not found\n") - return False + print("The variable is not found\n") + return False converted_solution[var].append(temp) elif isinstance(v, list): converted_solution[var].append([]) @@ -551,26 +550,24 @@ def convert_simulated_annealing_solution(self, solution: dict[str, float]) -> di if next(iter(el[0].variables)) not in solution: print("The variable is not found\n") return False - else: + elif ( + next(iter(self.binary_variables_name_weight[v1.name][0].variables)) in solution + ): if ( - next(iter(self.binary_variables_name_weight[v1.name][0].variables)) - in solution - ): - if ( - solution[ - next(iter(self.binary_variables_name_weight[v1.name][0].variables)) - ] - == 1 - ) and len(self.binary_variables_name_weight[v1.name]) > 0: - if len(self.binary_variables_name_weight[v1.name]) > 1: - temp += self.binary_variables_name_weight[v1.name][1] - else: - temp += 1 - if len(self.binary_variables_name_weight[v1.name]) == 3: - temp += self.binary_variables_name_weight[v1.name][2] - else: - print("The variable is not found\n") - return False + solution[ + next(iter(self.binary_variables_name_weight[v1.name][0].variables)) + ] + == 1 + ) and len(self.binary_variables_name_weight[v1.name]) > 0: + if len(self.binary_variables_name_weight[v1.name]) > 1: + temp += self.binary_variables_name_weight[v1.name][1] + else: + temp += 1 + if len(self.binary_variables_name_weight[v1.name]) == 3: + temp += self.binary_variables_name_weight[v1.name][2] + else: + print("The variable is not found\n") + return False converted_solution[var][j].append(temp) else: @@ -598,27 +595,22 @@ def convert_simulated_annealing_solution(self, solution: dict[str, float]) -> di if next(iter(el[0].variables)) not in solution: print("The variable is not found\n") return False - else: + elif ( + next(iter(self.binary_variables_name_weight[v2.name][0].variables)) + in solution + ): if ( - next(iter(self.binary_variables_name_weight[v2.name][0].variables)) - in solution - ): - if ( - solution[ - next( - iter( - self.binary_variables_name_weight[v2.name][0].variables - ) - ) - ] - == 1 - ) and len(self.binary_variables_name_weight[v2.name]) > 1: - temp += self.binary_variables_name_weight[v2.name][1] - if len(self.binary_variables_name_weight[v2.name]) == 3: - temp += self.binary_variables_name_weight[v2.name][2] - else: - print("The variable is not found\n") - return False + solution[ + next(iter(self.binary_variables_name_weight[v2.name][0].variables)) + ] + == 1 + ) and len(self.binary_variables_name_weight[v2.name]) > 1: + temp += self.binary_variables_name_weight[v2.name][1] + if len(self.binary_variables_name_weight[v2.name]) == 3: + temp += self.binary_variables_name_weight[v2.name][2] + else: + print("The variable is not found\n") + return False converted_solution[var][j][k].append(temp) k += 1 j += 1 @@ -699,9 +691,11 @@ def _unitary_encoding( binary_variables_name_weight[self.name].append("unitary") for w in range(1, samples + 1): if w == 1: - binary_variables_name_weight[self.name].append( - (boolean_var(letter + format(i)), w * unitary_weight, min_val) - ) + binary_variables_name_weight[self.name].append(( + boolean_var(letter + format(i)), + w * unitary_weight, + min_val, + )) else: binary_variables_name_weight[self.name].append((boolean_var(letter + format(i)), w * unitary_weight)) i += 1 @@ -737,9 +731,11 @@ def _domain_well_encoding( binary_variables_name_weight[self.name].append("domain well") for w in range(1, samples + 1): if w == 1: - binary_variables_name_weight[self.name].append( - (boolean_var(letter + format(i)), w * unitary_weight, min_val) - ) + binary_variables_name_weight[self.name].append(( + boolean_var(letter + format(i)), + w * unitary_weight, + min_val, + )) else: binary_variables_name_weight[self.name].append((boolean_var(letter + format(i)), w * unitary_weight)) constraints.append((letter + format(i) + ">=" + letter + format(i - 1), True, False, False)) @@ -820,9 +816,11 @@ def _arithmetic_progression_encoding( binary_variables_name_weight[self.name].append("arithmetic progression") for w in range(1, samples): if w == 1: - binary_variables_name_weight[self.name].append( - (boolean_var(letter + format(i)), w * unitary_weight, min_val) - ) + binary_variables_name_weight[self.name].append(( + boolean_var(letter + format(i)), + w * unitary_weight, + min_val, + )) else: binary_variables_name_weight[self.name].append((boolean_var(letter + format(i)), w * unitary_weight)) i += 1 @@ -875,9 +873,11 @@ def _bounded_coefficient_encoding( eta = floor(v / ux) binary_variables_name_weight[self.name] = [] binary_variables_name_weight[self.name].append("bounded coefficient") - binary_variables_name_weight[self.name].append( - (boolean_var(letter + format(i)), base**lower_power, min_val) - ) + binary_variables_name_weight[self.name].append(( + boolean_var(letter + format(i)), + base**lower_power, + min_val, + )) i += 1 for k in range(lower_power + 1, ro): @@ -1040,67 +1040,65 @@ def move_to_binary( binary_variables_name_weight, i, constraints, values, letter ) self._encoding_mechanism = "dictionary" - else: - if self._encoding_mechanism == "dictionary": + elif self._encoding_mechanism == "dictionary": + values = list(np.arange(self._min, self._max + self.precision, self.precision)) + binary_variables_name_weight, constraints, i = self._dictionary_encoding( + binary_variables_name_weight, i, constraints, values, letter + ) + elif self._encoding_mechanism == "unitary": + binary_variables_name_weight, i = self._unitary_encoding( + binary_variables_name_weight, i, self._max, self._min, self.precision, letter + ) + elif self._encoding_mechanism == "domain well": + binary_variables_name_weight, constraints, i = self._domain_well_encoding( + binary_variables_name_weight, i, self._max, self._min, constraints, self.precision, letter + ) + elif self._encoding_mechanism.startswith("logarithmic"): + try: + base = int(self._encoding_mechanism.split(" ")[1]) + binary_variables_name_weight, i = self._logarithmic_encoding( + binary_variables_name_weight, i, self._max, self._min, base, int(self.precision), letter + ) + self.precision = base**self.precision + except TypeError: values = list(np.arange(self._min, self._max + self.precision, self.precision)) binary_variables_name_weight, constraints, i = self._dictionary_encoding( binary_variables_name_weight, i, constraints, values, letter ) - elif self._encoding_mechanism == "unitary": - binary_variables_name_weight, i = self._unitary_encoding( - binary_variables_name_weight, i, self._max, self._min, self.precision, letter - ) - elif self._encoding_mechanism == "domain well": - binary_variables_name_weight, constraints, i = self._domain_well_encoding( - binary_variables_name_weight, i, self._max, self._min, constraints, self.precision, letter - ) - elif self._encoding_mechanism.startswith("logarithmic"): - try: - base = int(self._encoding_mechanism.split(" ")[1]) - binary_variables_name_weight, i = self._logarithmic_encoding( - binary_variables_name_weight, i, self._max, self._min, base, int(self.precision), letter - ) - self.precision = base**self.precision - except TypeError: - values = list(np.arange(self._min, self._max + self.precision, self.precision)) - binary_variables_name_weight, constraints, i = self._dictionary_encoding( - binary_variables_name_weight, i, constraints, values, letter - ) - self._encoding_mechanism = "dictionary" + self._encoding_mechanism = "dictionary" - elif self._encoding_mechanism == "arithmetic progression": - binary_variables_name_weight, i = self._arithmetic_progression_encoding( - binary_variables_name_weight, i, self._max, self._min, self.precision, letter + elif self._encoding_mechanism == "arithmetic progression": + binary_variables_name_weight, i = self._arithmetic_progression_encoding( + binary_variables_name_weight, i, self._max, self._min, self.precision, letter + ) + elif self._encoding_mechanism.startswith("bounded coefficient"): + try: + ux = int(self._encoding_mechanism.split(" ")[2]) + binary_variables_name_weight, i = self._bounded_coefficient_encoding( + binary_variables_name_weight, + i, + ux, + self._max, + self._min, + 2, + int(log2(self.precision)), + letter, ) - elif self._encoding_mechanism.startswith("bounded coefficient"): - try: - ux = int(self._encoding_mechanism.split(" ")[2]) - binary_variables_name_weight, i = self._bounded_coefficient_encoding( - binary_variables_name_weight, - i, - ux, - self._max, - self._min, - 2, - int(log(self.precision, 2)), - letter, - ) - except TypeError: - values = list(np.arange(self._min, self._max + self.precision, self.precision)) - binary_variables_name_weight, constraints, i = self._dictionary_encoding( - binary_variables_name_weight, i, constraints, values, letter - ) - self._encoding_mechanism = "dictionary" - else: - if (1 / self.precision) % 2 == 0: - binary_variables_name_weight, i = self._logarithmic_encoding( - binary_variables_name_weight, i, self._max, self._min, 2, int(log(self.precision, 2)), letter - ) - self._encoding_mechanism = "logarithmic 2" - else: - binary_variables_name_weight, i = self._arithmetic_progression_encoding( - binary_variables_name_weight, i, self._max, self._min, self.precision, letter - ) - self._encoding_mechanism = "arithmetic progression" + except TypeError: + values = list(np.arange(self._min, self._max + self.precision, self.precision)) + binary_variables_name_weight, constraints, i = self._dictionary_encoding( + binary_variables_name_weight, i, constraints, values, letter + ) + self._encoding_mechanism = "dictionary" + elif (1 / self.precision) % 2 == 0: + binary_variables_name_weight, i = self._logarithmic_encoding( + binary_variables_name_weight, i, self._max, self._min, 2, int(log2(self.precision)), letter + ) + self._encoding_mechanism = "logarithmic 2" + else: + binary_variables_name_weight, i = self._arithmetic_progression_encoding( + binary_variables_name_weight, i, self._max, self._min, self.precision, letter + ) + self._encoding_mechanism = "arithmetic progression" return binary_variables_name_weight, constraints, i diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 1fdc018..39abfe9 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -967,20 +967,20 @@ def test_problem(lambda_strategy: str) -> None: reference_qubo_dict_re = {} for key in reference_qubo_dict: reference_qubo_dict_re[tuple(sorted(key))] = reference_qubo_dict[key] - if lambda_strategy == "upper_bound_only_positive" or lambda_strategy == "upper lower bound naive": - assert [52.25 * 1.1] * 2 == lambdas + if lambda_strategy in {"upper_bound_only_positive", "upper lower bound naive"}: + assert lambdas == [52.25 * 1.1] * 2 assert dict(sorted(qubo_re.items())) == dict(sorted(reference_qubo_dict_re.items())) elif lambda_strategy == "maximum_coefficient": - assert [10.0 * 1.1] * 2 == lambdas + assert lambdas == [10.0 * 1.1] * 2 assert dict(sorted(qubo_re.items())) == dict(sorted(reference_qubo_dict_re.items())) - elif lambda_strategy == "VLM" or lambda_strategy == "MOMC": - assert [12.0 * 1.1] * 2 == lambdas + elif lambda_strategy in {"VLM", "MOMC"}: + assert lambdas == [12.0 * 1.1] * 2 assert dict(sorted(qubo_re.items())) == dict(sorted(reference_qubo_dict_re.items())) elif lambda_strategy == "MOC": - assert [7 * 1.1, 6 * 1.1] == lambdas + assert lambdas == [7 * 1.1, 6 * 1.1] assert dict(sorted(qubo_re.items())) == dict(sorted(reference_qubo_dict_re.items())) elif lambda_strategy == "upper lower bound posiform and negaform method": - assert [31.625 * 1.1] * 2 == lambdas + assert lambdas == [31.625 * 1.1] * 2 assert dict(sorted(qubo_re.items())) == dict(sorted(reference_qubo_dict_re.items())) @@ -1011,7 +1011,7 @@ def test_simulated_annealer_solver(lambda_strategy: str) -> None: solver = Solver() sol = solver.solve_simulated_annealing(problem, lambda_strategy=lambda_strategy) if isinstance(sol, Solution): - all_satisfy, each_satisfy = sol.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = sol.check_constraint_optimal_solution() assert sol.best_solution == {"a": 0.0, "b": 3.0, "c": -1.5} assert sol.best_energy < -2.24 # (the range if for having no issues with numerical errors) assert sol.best_energy > -2.26 @@ -1080,7 +1080,7 @@ def test_simulated_annealer_solver_constrained(lambda_strategy: str, constraint_ solver = Solver() solution = solver.solve_simulated_annealing(problem, lambda_strategy=lambda_strategy) if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() if constraint_expr == "c >= 1": assert solution.best_solution == {"a": 0.0, "b": -1.0, "c": 1.0} or not all_satisfy assert ( @@ -1174,7 +1174,7 @@ def test_simulated_annealer_solver_constrained_lambda_update_mechanism( ) solver.get_lambda_updates() if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() if constraint_expr == "c >= 1": assert solution.best_solution == {"a": 0.0, "b": -1.0, "c": 1.0} or not all_satisfy assert ( @@ -1376,7 +1376,7 @@ def test_simulated_annealer_solver_constrained_lambda_update_mechanism_and_strat ) solver.get_lambda_updates() if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() if constraint_expr == "c >= 1": assert solution.best_solution == {"a": 0.0, "b": -1.0, "c": 1.0} or not all_satisfy assert ( @@ -1472,7 +1472,7 @@ def test_simulated_annealing_cost_function_matrix( ) solver.get_lambda_updates() if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() if constraint_expr == "M1_0_1 >= 1": assert ( solution.best_solution == {"M1": [[-1, 2]], "M2": [[2], [-1]]} @@ -1504,7 +1504,7 @@ def test_gas_solver_basic() -> None: solver = Solver() solution = solver.solve_grover_adaptive_search_qubo(problem, qubit_values=6, num_runs=10) if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() assert solution.best_solution == {"a": 1.0, "b": 0.0, "c": 1.0} print(solution.best_solution) assert solution.best_energy < -5.9 # (the range if for having no issues with numerical errors) @@ -1534,7 +1534,7 @@ def test_qaoa_solver_qubo_basic() -> None: num_runs=10, ) if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() assert solution.best_solution == {"a": 1.0, "b": 0.0, "c": 1.0} print(solution.best_solution) assert solution.best_energy < -5.9 # (the range if for having no issues with numerical errors) @@ -1564,7 +1564,7 @@ def test_vqe_solver_qubo_basic() -> None: num_runs=10, ) if isinstance(solution, Solution): - all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() assert solution.best_solution == {"a": 1.0, "b": 0.0, "c": 1.0} print(solution.best_solution) assert solution.best_energy < -5.9 # (the range if for having no issues with numerical errors) From 033b0e6c83ab6014848b01e16166d46d201078b2 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 12:40:56 +0200 Subject: [PATCH 17/89] =?UTF-8?q?=E2=9C=A8=20add=20dependabot=20configurat?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6b89cc9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + groups: + github-actions: + patterns: + - "*" + schedule: + interval: "weekly" + day: "wednesday" + time: "06:00" + timezone: "Europe/Vienna" + + - package-ecosystem: "pip" + directory: "/" + groups: + python-dependencies: + patterns: + - "*" + schedule: + interval: "weekly" + day: "friday" + time: "06:00" + timezone: "Europe/Vienna" From 95c7e6e4d2b2ecd0baa767f4c8850a0c5c819672 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:04:48 +0200 Subject: [PATCH 18/89] =?UTF-8?q?=F0=9F=94=A7=20add=20mypy=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 79667a1..1c7ae9f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -75,6 +75,7 @@ repos: args: [] additional_dependencies: - pytest + - numpy # Also run Black on examples in the documentation - repo: https://github.com/adamchainz/blacken-docs From fff598aeb35b5d103a77d3c887e838b9e5193df8 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:06:18 +0200 Subject: [PATCH 19/89] =?UTF-8?q?=E2=9C=A8=20enable=20support=20for=20Pyth?= =?UTF-8?q?on=203.8=20to=203.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noxfile.py | 2 +- pyproject.toml | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/noxfile.py b/noxfile.py index f35e6d6..d42d3ea 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,7 +15,7 @@ nox.needs_version = ">=2024.3.2" nox.options.default_venv_backend = "uv|virtualenv" -PYTHON_ALL_VERSIONS = ["3.10", "3.11"] +PYTHON_ALL_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] BUILD_REQUIREMENTS = [ "setuptools==66.1.0", diff --git a/pyproject.toml b/pyproject.toml index 0734042..9afc729 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] requires = [ - "setuptools>=61", + "setuptools>=66.1", "setuptools_scm>=7", ] build-backend = "setuptools.build_meta" @@ -15,7 +15,7 @@ authors = [ ] keywords = ["MQT", "quantum computing", "optimization", "QUBO"] license = { file = "LICENSE" } -requires-python = ">=3.10,<3.12" +requires-python = ">=3.8" dynamic = ["version"] dependencies = [ @@ -46,8 +46,11 @@ classifiers = [ "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Intended Audience :: Science/Research", "Natural Language :: English", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", @@ -130,15 +133,15 @@ precision = 1 [tool.mypy] -mypy_path = "$MYPY_CONFIG_FILE_DIR/src" files = ["src", "tests"] -python_version = "3.11" -strict = true +mypy_path = ["$MYPY_CONFIG_FILE_DIR/src"] +python_version = "3.8" +warn_unused_configs = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] -warn_unreachable = true +strict = true +disallow_untyped_defs = false explicit_package_bases = true -no_implicit_reexport = true -pretty = true +warn_unreachable = true [[tool.mypy.overrides]] From 968eba3aeda99ff66a38eccbb5ebe06b924c908d Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:06:51 +0200 Subject: [PATCH 20/89] =?UTF-8?q?=F0=9F=A9=B9=20fix=20up=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noxfile.py | 20 +++----------------- pyproject.toml | 30 ++++++++++++------------------ 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/noxfile.py b/noxfile.py index d42d3ea..06ae669 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,23 +18,9 @@ PYTHON_ALL_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] BUILD_REQUIREMENTS = [ - "setuptools==66.1.0", - "setuptools_scm==7.0.1", - "wheel==0.40", - "matplotlib==3.8", - "sympy==1.9", - "qiskit==0.45.3", - "qiskit_optimization==0.4.0", - "qiskit_ibm_runtime==0.14.0", - "scikit-learn==1.3", - "dimod==0.12.7", - "docplex==2.22.213", - "dwave-samplers==1.2", - "dwave-system==1.20", - "pandas==2.1", - "qubovert==1.0", - "pytest==7.4.0", - "tomli==2.0.1", + "setuptools>=66.1", + "setuptools_scm>=7.2", + "wheel>=0.40", ] if os.environ.get("CI", None): diff --git a/pyproject.toml b/pyproject.toml index 9afc729..933bd85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,23 +19,17 @@ requires-python = ">=3.8" dynamic = ["version"] dependencies = [ - "setuptools==66.1.0", - "setuptools_scm==7.0.1", - "wheel==0.40", - "matplotlib==3.8", - "sympy==1.9", - "qiskit==0.45.3", - "qiskit_optimization==0.4.0", - "qiskit_ibm_runtime==0.14.0", - "scikit-learn==1.3", - "dimod==0.12.7", - "docplex==2.22.213", - "dwave-samplers==1.2", - "dwave-system==1.20", - "pandas==2.1", - "qubovert==1.0", - "pytest==7.4.0", - "tomli==2.0.1" + "qiskit>=1.0", + "qiskit_optimization>=0.6", + "qiskit_aer>=0.14", + "pandas>=2.1.2", + "numpy>=1.26", + "qubovert>=1.2.5", + "qiskit_ibm_runtime>=0.21", + "matplotlib>=3.8", + "docplex>=2.21.207", + "dwave-system>=1.21.0", + "dwave-samplers>=1.2.0", ] classifiers = [ @@ -59,7 +53,6 @@ classifiers = [ [project.optional-dependencies] test = ["pytest>=7.2"] coverage = ["mqt.qao[test]", "pytest-cov>=4"] -dev = ["mqt.qao[coverage]"] docs = [ "furo>=2023.08.17", "sphinx~=7.0", @@ -75,6 +68,7 @@ docs = [ "sphinx-autodoc-typehints", "qiskit[visualization]", ] +dev = ["mqt.qao[coverage,docs]"] [project.urls] Homepage = "https://github.com/cda-tum/mqt-qao" From f909656824ee34c3f9ae1306c5e0a33dec865e12 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:07:03 +0200 Subject: [PATCH 21/89] =?UTF-8?q?=F0=9F=A9=B9=20fix=20up=20project=20confi?= =?UTF-8?q?guration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 76 ++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 933bd85..c3d42e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ authors = [ { name = "Deborah Volpe", email = "deborah.volpe@polito.it"}, { name = "Nils Quetschlich", email = "nils.quetschlich@tum.de" }, ] -keywords = ["MQT", "quantum computing", "optimization", "QUBO"] +keywords = ["MQT", "quantum-computing", "optimization", "QUBO"] license = { file = "LICENSE" } requires-python = ">=3.8" dynamic = ["version"] @@ -80,37 +80,16 @@ Research = "https://www.cda.cit.tum.de/research/quantum/" [tool.pytest.ini_options] -pythonpath = ["./src"] minversion = "7.2" testpaths = ["tests"] addopts = ["-ra", "--strict-markers", "--strict-config", "--showlocals"] -log_cli_level = "INFO" +log_cli_level = "info" xfail_strict = true filterwarnings = [ "error", - "ignore:.*pkg_resources.*:DeprecationWarning:", - "ignore:.*sre_.*:DeprecationWarning:", - "ignore:.*Rigetti.*:UserWarning:", - "ignore:.*Values in x.*:RuntimeWarning:", - "ignore:.*The Rebase2QuditGatePass has moved to bqskit.passes.retarget.two.*:DeprecationWarning:", - "ignore:.*The least populated class in y has only 3 members, which is less than n_splits=5.*:UserWarning:", - "ignore:.*divide by zero encountered in det.*:RuntimeWarning:", - "ignore:.*invalid value encountered in det.*:RuntimeWarning:", - "ignore:..*env.action_masks to get variables from other wrappers is deprecated and will be removed in v1.0.*:UserWarning:", - "ignore::SyntaxWarning:.*(docplex).*", - "ignore::DeprecationWarning:.*(docplex).*", - "ignore:.*pytorch.*:UserWarning:", - "ignore::DeprecationWarning:.*(importlib).*", - "ignore:.*:DeprecationWarning:qiskit.*", - "ignore:.*:PendingDeprecationWarning:qiskit.*", - "ignore:.*:ImportWarning:.*", - "ignore:.*:DeprecationWarning:qiskit.providers.ibmq.*", - "ignore:.*qiskit.algorithms.*:DeprecationWarning:.*", - "ignore::sklearn.exceptions.InconsistentVersionWarning:sklearn:", + "ignore:.*Qiskit with Python 3.8.*:DeprecationWarning:", ] -[tool.check-wheel-contents] -ignore = "W002" [tool.coverage] run.source = ["mqt.qao"] @@ -139,7 +118,20 @@ warn_unreachable = true [[tool.mypy.overrides]] -module = ["qubovert.*", "sympy.*", "dwave.samplers.*", "dwave.system.*", "docplex.*", "qiskit.*", "qiskit_optimization.*", "qiskit_ibm_provider.*", "matplotlib.*", "pandas.*", "pypfopt.*", "sklearn.*"] +module = [ + "qiskit.*", + "qiskit_optimization.*", + "qiskit_algorithms.*", + "qiskit_aer.*", + "matplotlib.*", + "qubovert.*", + "sympy.*", + "qiskit_ibm_runtime.*", + "matplotlib.*", + "docplex.*", + "dimod.*", + "dwave.*" +] ignore_missing_imports = true @@ -149,6 +141,7 @@ extend-include = ["*.ipynb"] src = ["src"] preview = true unsafe-fixes = true + [tool.ruff.lint] extend-select = [ "A", # flake8-builtins @@ -184,30 +177,45 @@ extend-select = [ "SLOT", # flake8-slots "SIM", # flake8-simplify "TCH", # flake8-type-checking - "TID", # flake8-tidy-imports + "TID251", # flake8-tidy-imports.banned-api "TRY", # tryceratops "UP", # pyupgrade "YTT", # flake8-2020 ] ignore = [ - "ANN101", # Missing type annotation for self in method - "ANN102", # Missing type annotation for cls in classmethod + "ANN101", # Missing type annotation for `self` in method + "ANN102", # Missing type annotation for `cls` in classmethod "ISC001", # Conflicts with formatter - "E501", # Line too long (Black is enough) - "PLR", # Design related pylint codes + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "PLC0415", # Import should be at top of file + "PT004", # Incorrect, just usefixtures instead. "S101", # Use of assert detected - "I001", # isort: Missing import + "S404", # `subprocess` module is possibly insecure ] -flake8-unused-arguments.ignore-variadic-names = true isort.required-imports = ["from __future__ import annotations"] +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"typing.Callable".msg = "Use collections.abc.Callable instead." +"typing.Iterator".msg = "Use collections.abc.Iterator instead." +"typing.Mapping".msg = "Use collections.abc.Mapping instead." +"typing.Sequence".msg = "Use collections.abc.Sequence instead." +"typing.Set".msg = "Use collections.abc.Set instead." +"typing.Self".msg = "Use scikit_build_core._compat.typing.Self instead." +"typing_extensions.Self".msg = "Use scikit_build_core._compat.typing.Self instead." +"typing.assert_never".msg = "Use scikit_build_core._compat.typing.assert_never instead." +"importlib.resources".msg = "Use scikit_build_core._compat.importlib.resources instead." +"importlib_resources".msg = "Use scikit_build_core._compat.importlib.resources instead." + [tool.ruff.lint.per-file-ignores] -"*.pyi" = ["D"] # pydocstyle +"tests/**" = ["T20", "ANN"] +"docs/**" = ["T20"] +"noxfile.py" = ["T20", "TID251"] +"*.pyi" = ["D418", "PYI021"] # pydocstyle "*.ipynb" = [ "D", # pydocstyle "E402", # Allow imports to appear anywhere in Jupyter notebooks "I002", # Allow missing `from __future__ import annotations` import - "I001", # Allow missing unsorted import ] [tool.ruff.lint.pydocstyle] From f9a75a98ee4a3f856bfba07cbd3f8a0342fa1a10 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:07:23 +0200 Subject: [PATCH 22/89] =?UTF-8?q?=F0=9F=A9=B9=20fix=20up=20package=20confi?= =?UTF-8?q?guration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/qao/constraints.py | 2 +- src/mqt/qao/objectivefunction.py | 2 +- src/mqt/qao/problem.py | 4 +++- src/mqt/qao/solvers.py | 34 ++++++++++++++------------------ tests/test_evaluation.py | 20 ------------------- 5 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index f2b7346..ce56ead 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -7,7 +7,7 @@ # for managing symbols from sympy import Expr, expand -from mqt.qao.variables import Variables +from .variables import Variables class Constraints: diff --git a/src/mqt/qao/objectivefunction.py b/src/mqt/qao/objectivefunction.py index e4ad8bf..6e79c7c 100644 --- a/src/mqt/qao/objectivefunction.py +++ b/src/mqt/qao/objectivefunction.py @@ -8,7 +8,7 @@ if TYPE_CHECKING: from qubovert import PUBO - from mqt.qao.variables import Variables + from .variables import Variables class ObjectiveFunction: diff --git a/src/mqt/qao/problem.py b/src/mqt/qao/problem.py index ca99306..1b97379 100644 --- a/src/mqt/qao/problem.py +++ b/src/mqt/qao/problem.py @@ -7,7 +7,9 @@ import numpy as np from qubovert import PUBO -from mqt.qao import Constraints, ObjectiveFunction, Variables +from .constraints import Constraints +from .objectivefunction import ObjectiveFunction +from .variables import Variables class Problem: diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index e8f40fa..85ecabd 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -14,12 +14,12 @@ from dwave.samplers import SimulatedAnnealingSampler from dwave.system import DWaveSampler, EmbeddingComposite from matplotlib import rc -from qiskit.algorithms import QAOA, VQE from qiskit.circuit import Parameter, QuantumCircuit from qiskit.circuit.library import TwoLocal from qiskit.exceptions import QiskitError -from qiskit.providers.basicaer import BasicAer -from qiskit_ibm_runtime import QiskitRuntimeService # type: ignore[import-untyped] +from qiskit_aer.backends import AerSimulator +from qiskit_algorithms import QAOA, VQE +from qiskit_ibm_runtime import QiskitRuntimeService from qiskit_optimization.algorithms import ( GroverOptimizer, MinimumEigenOptimizationResult, @@ -33,16 +33,12 @@ from collections.abc import Callable from dimod import SampleSet - from qiskit.algorithms.optimizers import Optimizer - from qiskit.opflow import ( - ExpectationBase, - GradientBase, - OperatorBase, - ) + from qiskit_algorithms.optimizers import Optimizer + from qiskit_algorithms.gradients import BaseEstimatorGradient from qiskit_optimization.problems import QuadraticProgram -from mqt.qao.problem import Problem +from .problem import Problem class Solver: @@ -461,14 +457,14 @@ def solve_grover_adaptive_search_qubo( backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen simulator doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() else: try: QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, quantum_instance=backend) if save_time: @@ -627,14 +623,14 @@ def solve_qaoa_qubo( backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() else: try: QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() qaoa_mes = QAOA( quantum_instance=backend, optimizer=optimizer, @@ -723,7 +719,7 @@ def solve_vqe_qubo( optimizer: Optimizer | None = None, ansatz: QuantumCircuit | OperatorBase | None = None, initial_point: np.ndarray[Any, Any] | None = None, - gradient: GradientBase | Callable[[np.ndarray[Any, Any] | list[Any]], list[Any]] | None = None, + gradient: BaseEstimatorGradient | Callable[[np.ndarray[Any, Any] | list[Any]], list[Any]] | None = None, expectation: ExpectationBase | None = None, include_custom: bool = False, max_evals_grouped: int = 1, @@ -779,14 +775,14 @@ def solve_vqe_qubo( backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() else: try: QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) backend = QiskitRuntimeService().backend(backend_name) except QiskitError: print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = BasicAer.get_backend("qasm_simulator") + backend = AerSimulator() vqe_mes = VQE( quantum_instance=backend, optimizer=optimizer, @@ -1000,7 +996,7 @@ def create_dwave_annealing_solution( self.energies.append(sample[1] + offset) self.best_energy = samples.first.energy + offset - for sample in list(samples.samples()): # type: ignore[no-untyped-call] + for sample in list(samples.samples()): converted_sol = self.problem.variables.convert_simulated_annealing_solution(pubo.convert_solution(sample)) if isinstance(converted_sol, dict): self.solutions.append(converted_sol) @@ -1176,7 +1172,7 @@ def show_cumulative( plt.savefig(filename + ".pdf", format="pdf") plt.close() elif show: - plt.show() # type: ignore[no-untyped-call] + plt.show() def valid_solutions(self, weak: bool = True) -> float: """function for evaluating the rate of valid solution and the amount of violations diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 39abfe9..151b637 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -17,26 +17,6 @@ from mqt.qao.solvers import Solution, Solver from mqt.qao.variables import Variables -# from dwave.cloud import Client - - -def test_example() -> None: - """Expected type of final code: - Problem = Problem - variables = Problem.variables.add_....._variables(.....) - def f(var): - .... - Problem.objective_function.add_objective_function(f(var)) - Problem.constraints.add_constraints(....) - # With an eventual option for saving more information (Problem final size, etc.) - decoded_best_solution, Energy = Problem.solve() - # And eventually for knowing something about resolution statistics - Problem.statistics() - - """ - Variables() - assert 1 == 1 - def test_binary_only() -> None: """Test only the construction of binary variables""" From d5ebb0cee43a382a8ac87b98ffd05a29f7bfd7ee Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 13:07:41 +0000 Subject: [PATCH 23/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/qao/solvers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index 85ecabd..2ef8fdb 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -33,8 +33,8 @@ from collections.abc import Callable from dimod import SampleSet - from qiskit_algorithms.optimizers import Optimizer from qiskit_algorithms.gradients import BaseEstimatorGradient + from qiskit_algorithms.optimizers import Optimizer from qiskit_optimization.problems import QuadraticProgram From a153ee9a40b191ae1eff5f4ca493127ea1ada37c Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:21:06 +0200 Subject: [PATCH 24/89] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20try=20to=20fix=20dat?= =?UTF-8?q?etime=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noxfile.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noxfile.py b/noxfile.py index 06ae669..be9f837 100644 --- a/noxfile.py +++ b/noxfile.py @@ -19,7 +19,7 @@ BUILD_REQUIREMENTS = [ "setuptools>=66.1", - "setuptools_scm>=7.2", + "setuptools_scm>=8.1", "wheel>=0.40", ] diff --git a/pyproject.toml b/pyproject.toml index c3d42e7..0338086 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] requires = [ "setuptools>=66.1", - "setuptools_scm>=7", + "setuptools_scm>=8.1", ] build-backend = "setuptools.build_meta" From a54deae55f781092b1b9f8d3ed2fb861301aa1f0 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:23:10 +0200 Subject: [PATCH 25/89] =?UTF-8?q?=F0=9F=94=A5=20remove=20redundant=20mypy?= =?UTF-8?q?=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/mypy.yml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/mypy.yml diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml deleted file mode 100644 index d2984e8..0000000 --- a/.github/workflows/mypy.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: mypy - -on: - pull_request: - push: - branches: - - main - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - lint: - runs-on: ubuntu-latest - name: Run my[py] linter - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - uses: pre-commit/action@v3.0.0 - with: - extra_args: mypy --all-files From 25ac45819eb07f8d01173d20c09179e4f935ff58 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:24:17 +0200 Subject: [PATCH 26/89] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20workflows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/codecov.yml | 3 --- .github/workflows/cd.yml | 2 +- .github/workflows/ci.yml | 6 +++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 2b41601..897f822 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -11,6 +11,3 @@ coverage: patch: default: threshold: 1% -codecov: - notify: - after_n_builds: 8 diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 36a7013..2f63168 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -7,7 +7,7 @@ on: jobs: python-packaging: name: 🐍 Packaging - uses: cda-tum/mqt-workflows/.github/workflows/reusable-python-packaging.yml@v1.0.0 + uses: cda-tum/mqt-workflows/.github/workflows/reusable-python-packaging.yml@v1.0.1 with: pure-python: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7126586..e0faf33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,13 @@ concurrency: jobs: change-detection: name: 🔍 Change - uses: cda-tum/mqt-workflows/.github/workflows/reusable-change-detection.yml@v1.0.0 + uses: cda-tum/mqt-workflows/.github/workflows/reusable-change-detection.yml@v1.0.1 python-tests: name: 🐍 Test needs: change-detection if: fromJSON(needs.change-detection.outputs.run-python-tests) - uses: cda-tum/mqt-workflows/.github/workflows/reusable-python-ci.yml@v1.0.0 + uses: cda-tum/mqt-workflows/.github/workflows/reusable-python-ci.yml@v1.0.1 secrets: token: ${{ secrets.CODECOV_TOKEN }} @@ -28,7 +28,7 @@ jobs: name: 📝 CodeQL needs: change-detection if: fromJSON(needs.change-detection.outputs.run-code-ql) - uses: cda-tum/mqt-workflows/.github/workflows/reusable-code-ql-python.yml@v1.0.0 + uses: cda-tum/mqt-workflows/.github/workflows/reusable-code-ql-python.yml@v1.0.1 required-checks-pass: # This job does nothing and is only used for branch protection name: 🚦 Check From 64ab83291a98c0bbf789298d1f2ff9fffa5d40ce Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:26:02 +0200 Subject: [PATCH 27/89] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20try=20to=20resolve?= =?UTF-8?q?=20pandas=20versioning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0338086..d598c50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,8 @@ dependencies = [ "qiskit>=1.0", "qiskit_optimization>=0.6", "qiskit_aer>=0.14", - "pandas>=2.1.2", + "pandas>=2.0; python_version < '3.9'", + "pandas>=2.1.2; python_version >= '3.9'", "numpy>=1.26", "qubovert>=1.2.5", "qiskit_ibm_runtime>=0.21", From e26d9826a949c568d08146fb9c7accbd5449bae4 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:32:39 +0200 Subject: [PATCH 28/89] =?UTF-8?q?=F0=9F=A9=B9=20fix=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0faf33..f0e32ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,8 +21,6 @@ jobs: needs: change-detection if: fromJSON(needs.change-detection.outputs.run-python-tests) uses: cda-tum/mqt-workflows/.github/workflows/reusable-python-ci.yml@v1.0.1 - secrets: - token: ${{ secrets.CODECOV_TOKEN }} code-ql: name: 📝 CodeQL From cbe80c3f6d572a07e6fb780575470452a96b6b05 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:37:46 +0200 Subject: [PATCH 29/89] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20try=20to=20fix=20num?= =?UTF-8?q?py=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d598c50..3c22205 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,8 @@ dependencies = [ "qiskit_aer>=0.14", "pandas>=2.0; python_version < '3.9'", "pandas>=2.1.2; python_version >= '3.9'", - "numpy>=1.26", + "numpy>=1.24; python_version < '3.9'", + "numpy>=1.26; python_version >= '3.9'", "qubovert>=1.2.5", "qiskit_ibm_runtime>=0.21", "matplotlib>=3.8", From b6e3ddb329ac72b9b8799f846b1bae3fcb8a28b8 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Wed, 29 May 2024 15:47:04 +0200 Subject: [PATCH 30/89] =?UTF-8?q?=F0=9F=94=A5=20drop=20Python=203.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noxfile.py | 2 +- pyproject.toml | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/noxfile.py b/noxfile.py index be9f837..3ddb987 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,7 +15,7 @@ nox.needs_version = ">=2024.3.2" nox.options.default_venv_backend = "uv|virtualenv" -PYTHON_ALL_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] +PYTHON_ALL_VERSIONS = ["3.9", "3.10", "3.11", "3.12"] BUILD_REQUIREMENTS = [ "setuptools>=66.1", diff --git a/pyproject.toml b/pyproject.toml index 3c22205..dc07a44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,17 +15,15 @@ authors = [ ] keywords = ["MQT", "quantum-computing", "optimization", "QUBO"] license = { file = "LICENSE" } -requires-python = ">=3.8" +requires-python = ">=3.9" dynamic = ["version"] dependencies = [ "qiskit>=1.0", "qiskit_optimization>=0.6", "qiskit_aer>=0.14", - "pandas>=2.0; python_version < '3.9'", - "pandas>=2.1.2; python_version >= '3.9'", - "numpy>=1.24; python_version < '3.9'", - "numpy>=1.26; python_version >= '3.9'", + "pandas>=2.1.2", + "numpy>=1.26", "qubovert>=1.2.5", "qiskit_ibm_runtime>=0.21", "matplotlib>=3.8", @@ -42,7 +40,6 @@ classifiers = [ "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -110,7 +107,7 @@ precision = 1 [tool.mypy] files = ["src", "tests"] mypy_path = ["$MYPY_CONFIG_FILE_DIR/src"] -python_version = "3.8" +python_version = "3.9" warn_unused_configs = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] strict = true From c4fb2b1a339835c6fea5a970746e3a101a3db536 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 30 May 2024 15:26:26 +0200 Subject: [PATCH 31/89] update qiskit version --- pyproject.toml | 1 - src/mqt/qao/constraints.py | 6 ++- src/mqt/qao/problem.py | 30 +++++++---- src/mqt/qao/solvers.py | 103 ++++++------------------------------- 4 files changed, 39 insertions(+), 101 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dc07a44..10eb5d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ dependencies = [ "pandas>=2.1.2", "numpy>=1.26", "qubovert>=1.2.5", - "qiskit_ibm_runtime>=0.21", "matplotlib>=3.8", "docplex>=2.21.207", "dwave-system>=1.21.0", diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index ce56ead..4dd6794 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -2163,7 +2163,8 @@ def _convert_expression_logic(self, expr: Expr, binary_variables_name_weight: di ret = binary_variables_name_weight[key][0] return ret - def _min_max_const_estimation(self, exp: PUBO) -> tuple[float, float, float]: + @staticmethod + def _min_max_const_estimation(exp: PUBO) -> tuple[float, float, float]: """function for estimating minimum and maximum value and the constraint value Keyword arguments: @@ -2186,7 +2187,8 @@ def _min_max_const_estimation(self, exp: PUBO) -> tuple[float, float, float]: min_val += exp[key] return min_val, max_val, const - def _expression_to_hamiltonian(self, exp: Expr, binary_variables_name_weight_val: list[Any]) -> PUBO: + @staticmethod + def _expression_to_hamiltonian(exp: Expr, binary_variables_name_weight_val: list[Any]) -> PUBO: """function for translating an expression in the problem variable into an Hamiltonian when is directly written with the inside binary variables Keyword arguments: diff --git a/src/mqt/qao/problem.py b/src/mqt/qao/problem.py index 1b97379..33f77d7 100644 --- a/src/mqt/qao/problem.py +++ b/src/mqt/qao/problem.py @@ -151,7 +151,8 @@ def update_lambda_cost_function( return self.pubo - def _upper_bound_with_only_positive_coefficient(self, cost_function: PUBO) -> float | bool: + @staticmethod + def _upper_bound_with_only_positive_coefficient(cost_function: PUBO) -> float | bool: """function for estimating the weights for constraints Keyword arguments: @@ -174,7 +175,8 @@ def _upper_bound_with_only_positive_coefficient(self, cost_function: PUBO) -> fl upperbound += cost_function[key] return upperbound - def _maximum_qubo_coefficient(self, cost_function: PUBO) -> float: + @staticmethod + def _maximum_qubo_coefficient(cost_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -198,7 +200,8 @@ def _maximum_qubo_coefficient(self, cost_function: PUBO) -> float: offset = cost_function[key] return max_coeff + offset - def _vlm(self, cost_function: PUBO) -> float: + @staticmethod + def _vlm(cost_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -226,7 +229,8 @@ def _vlm(self, cost_function: PUBO) -> float: n_sum[elem] -= cost_function[key] return float(np.max([np.array(list(p_sum.values())), np.array(list(n_sum.values()))])) - def _momc(self, cost_function: PUBO, constraint_function: PUBO) -> float: + @staticmethod + def _momc(cost_function: PUBO, constraint_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -275,7 +279,8 @@ def _momc(self, cost_function: PUBO, constraint_function: PUBO) -> float: return wc_max return max(1.0, wc_max / wg_min) - def _moc(self, cost_function: PUBO, constraint_function: PUBO) -> float: + @staticmethod + def _moc(cost_function: PUBO, constraint_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -339,7 +344,8 @@ def _moc(self, cost_function: PUBO, constraint_function: PUBO) -> float: val = v return max(1, val) - def upper_lower_bound_naive_method(self, cost_function: PUBO) -> float: + @staticmethod + def upper_lower_bound_naive_method(cost_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -359,7 +365,8 @@ def upper_lower_bound_naive_method(self, cost_function: PUBO) -> float: lower_bound += cost_function[key] return upper_bound - lower_bound - def upper_lower_bound_posiform_and_negaform_method(self, cost_function: PUBO) -> float: + @staticmethod + def upper_lower_bound_posiform_and_negaform_method(cost_function: PUBO) -> float: """function for estimating the weights for constraints Keyword arguments: @@ -394,7 +401,8 @@ def upper_lower_bound_posiform_and_negaform_method(self, cost_function: PUBO) -> upperbound += n_sum[key] return upperbound - lowerbound - def _sequential_penalty_increase(self, current_lambda: float) -> float: + @staticmethod + def _sequential_penalty_increase(current_lambda: float) -> float: """function for updating weights for constraints Keyword arguments: @@ -405,7 +413,8 @@ def _sequential_penalty_increase(self, current_lambda: float) -> float: """ return current_lambda * 10 - def _scaled_sequential_penalty_increase(self, current_lambda: float, wu: float, t: int) -> float: + @staticmethod + def _scaled_sequential_penalty_increase(current_lambda: float, wu: float, t: int) -> float: """function for updating weights for constraints Keyword arguments: @@ -419,7 +428,8 @@ def _scaled_sequential_penalty_increase(self, current_lambda: float, wu: float, scale_factor = wu ** (1 / t) return float(round(current_lambda * scale_factor)) - def _binary_search_penalty_algorithm(self, current_lambda: float, wu: float) -> float: + @staticmethod + def _binary_search_penalty_algorithm(current_lambda: float, wu: float) -> float: """function for updating weights for constraints Keyword arguments: diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index 2ef8fdb..122d0b4 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -16,15 +16,12 @@ from matplotlib import rc from qiskit.circuit import Parameter, QuantumCircuit from qiskit.circuit.library import TwoLocal -from qiskit.exceptions import QiskitError -from qiskit_aer.backends import AerSimulator -from qiskit_algorithms import QAOA, VQE -from qiskit_ibm_runtime import QiskitRuntimeService +from qiskit.primitives import Sampler +from qiskit_algorithms import QAOA, SamplingVQE from qiskit_optimization.algorithms import ( GroverOptimizer, - MinimumEigenOptimizationResult, MinimumEigenOptimizer, - OptimizationResult, + SolutionSample, ) from qiskit_optimization.translators import from_docplex_mp from qubovert import PUBO, QUBO @@ -33,7 +30,6 @@ from collections.abc import Callable from dimod import SampleSet - from qiskit_algorithms.gradients import BaseEstimatorGradient from qiskit_algorithms.optimizers import Optimizer from qiskit_optimization.problems import QuadraticProgram @@ -381,11 +377,6 @@ def solve_grover_adaptive_search_qubo( self, problem: Problem, auto_setting: bool = False, - simulator: bool = True, - backend_name: str = "qasm_simulator", - channel: str = "", - token: str = "", - instance: str = "", qubit_values: int = 0, coeff_precision: float = 1.0, threshold: int = 10, @@ -451,21 +442,7 @@ def solve_grover_adaptive_search_qubo( elif boundaries_estimation_method == "naive": qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)))) - if simulator: - try: # Load your IBM Quantum account - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen simulator doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() - else: - try: - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() - grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, quantum_instance=backend) + grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, sampler=Sampler()) if save_time: start = time_ns() @@ -511,7 +488,7 @@ def solve_grover_adaptive_search_qubo( elif boundaries_estimation_method == "naive": qubit_values = ceil(log2(abs(self.problem.upper_lower_bound_naive_method(scaled_qubo)))) - grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, quantum_instance=backend) + grover_optimizer = GroverOptimizer(qubit_values, num_iterations=threshold, sampler=Sampler()) if save_time: start = time_ns() @@ -545,21 +522,13 @@ def solve_qaoa_qubo( self, problem: Problem, auto_setting: bool = False, - simulator: bool = True, - backend_name: str = "qasm_simulator", - channel: str = "", - token: str = "", - instance: str = "", num_runs: int = 10, optimizer: Optimizer = None, reps: int = 1, initial_state: QuantumCircuit | None = None, - mixer: QuantumCircuit | OperatorBase = None, + mixer: QuantumCircuit = None, initial_point: np.ndarray[Any, Any] | None = None, - gradient: GradientBase | Callable[[np.ndarray[Any, Any] | list[Any]], list[Any]] | None = None, - expectation: ExpectationBase | None = None, - include_custom: bool = False, - max_evals_grouped: int = 1, + aggregation: float | Callable[[list[float]], float] | None = None, callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, max_lambda_update: int = 5, lambda_update_mechanism: str = "sequential penalty increase", @@ -617,31 +586,14 @@ def solve_qaoa_qubo( initial_state = QuantumCircuit(var_num) for _idx in range(var_num): initial_state.h(_idx) - if simulator: - try: - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() - else: - try: - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() qaoa_mes = QAOA( - quantum_instance=backend, + sampler=Sampler(), optimizer=optimizer, reps=reps, initial_state=initial_state, mixer=mixer, initial_point=initial_point, - gradient=gradient, - expectation=expectation, - include_custom=include_custom, - max_evals_grouped=max_evals_grouped, + aggregation=aggregation, callback=callback, ) qaoa = MinimumEigenOptimizer(qaoa_mes) @@ -710,19 +662,11 @@ def solve_vqe_qubo( self, problem: Problem, auto_setting: bool = False, - simulator: bool = True, - backend_name: str = "qasm_simulator", - channel: str = "", - token: str = "", - instance: str = "", num_runs: int = 10, optimizer: Optimizer | None = None, - ansatz: QuantumCircuit | OperatorBase | None = None, + ansatz: QuantumCircuit | None = None, initial_point: np.ndarray[Any, Any] | None = None, - gradient: BaseEstimatorGradient | Callable[[np.ndarray[Any, Any] | list[Any]], list[Any]] | None = None, - expectation: ExpectationBase | None = None, - include_custom: bool = False, - max_evals_grouped: int = 1, + aggregation: float | Callable[[list[float]], float] | None = None, callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, max_lambda_update: int = 5, lambda_update_mechanism: str = "sequential penalty increase", @@ -769,29 +713,12 @@ def solve_vqe_qubo( if auto_setting and ansatz is None: ansatz = TwoLocal(num_qubits=len(self.qubo.variables), rotation_blocks="ry", entanglement_blocks="cz") - if simulator: - try: - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() - else: - try: - QiskitRuntimeService.save_account(channel=channel, token=token, instance=instance, overwrite=True) - backend = QiskitRuntimeService().backend(backend_name) - except QiskitError: - print("The chosen backend doesn't exist or the IBM cannot be used. Qasm simulator will used.") - backend = AerSimulator() - vqe_mes = VQE( - quantum_instance=backend, + vqe_mes = SamplingVQE( + sampler=Sampler(), optimizer=optimizer, ansatz=ansatz, initial_point=initial_point, - gradient=gradient, - expectation=expectation, - include_custom=include_custom, - max_evals_grouped=max_evals_grouped, + aggregation=aggregation, callback=callback, ) vqe = MinimumEigenOptimizer(vqe_mes) @@ -1018,7 +945,7 @@ def create_dwave_annealing_solution( def create_qiskit_qubo_solution( self, - res: list[MinimumEigenOptimizationResult] | list[OptimizationResult], + res: list[SolutionSample], pubo: PUBO, qubo: QUBO, time: float = -1.0, From 91f30b334b95faa91afe44990424100b3f8ea002 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 30 May 2024 17:00:10 +0200 Subject: [PATCH 32/89] update qiskit version --- pyproject.toml | 1 + src/mqt/qao/solvers.py | 7 ++++--- tests/__init__.py | 5 +++++ tests/test_evaluation.py | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/__init__.py diff --git a/pyproject.toml b/pyproject.toml index 10eb5d2..e13bb21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ Research = "https://www.cda.cit.tum.de/research/quantum/" [tool.pytest.ini_options] minversion = "7.2" testpaths = ["tests"] +pythonpath = ["src"] addopts = ["-ra", "--strict-markers", "--strict-config", "--showlocals"] log_cli_level = "info" xfail_strict = true diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index 122d0b4..c4d5ad1 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -18,6 +18,7 @@ from qiskit.circuit.library import TwoLocal from qiskit.primitives import Sampler from qiskit_algorithms import QAOA, SamplingVQE +from qiskit_algorithms.optimizers import COBYLA from qiskit_optimization.algorithms import ( GroverOptimizer, MinimumEigenOptimizer, @@ -523,7 +524,7 @@ def solve_qaoa_qubo( problem: Problem, auto_setting: bool = False, num_runs: int = 10, - optimizer: Optimizer = None, + optimizer: Optimizer = COBYLA(), reps: int = 1, initial_state: QuantumCircuit | None = None, mixer: QuantumCircuit = None, @@ -663,7 +664,7 @@ def solve_vqe_qubo( problem: Problem, auto_setting: bool = False, num_runs: int = 10, - optimizer: Optimizer | None = None, + optimizer: Optimizer = COBYLA(), ansatz: QuantumCircuit | None = None, initial_point: np.ndarray[Any, Any] | None = None, aggregation: float | Callable[[list[float]], float] | None = None, @@ -710,7 +711,7 @@ def solve_vqe_qubo( compilation_time = -1 logging.getLogger("qiskit").setLevel(logging.ERROR) res = [] - if auto_setting and ansatz is None: + if auto_setting or ansatz is None: ansatz = TwoLocal(num_qubits=len(self.qubo.variables), rotation_blocks="ry", entanglement_blocks="cz") vqe_mes = SamplingVQE( diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e2678bd --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,5 @@ +"""MQT QAO. + +This file is part of the MQT QAO library released under the MIT license. +See README.md or go to https://github.com/cda-tum/mqt-predictor for more information. +""" \ No newline at end of file diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 151b637..ca42fe5 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -1485,6 +1485,7 @@ def test_gas_solver_basic() -> None: solution = solver.solve_grover_adaptive_search_qubo(problem, qubit_values=6, num_runs=10) if isinstance(solution, Solution): all_satisfy, _each_satisfy = solution.check_constraint_optimal_solution() + print(solution.best_solution) assert solution.best_solution == {"a": 1.0, "b": 0.0, "c": 1.0} print(solution.best_solution) assert solution.best_energy < -5.9 # (the range if for having no issues with numerical errors) From 185cf2c9d5234f20e011a7dbef5230b27a46e3cd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 15:02:55 +0000 Subject: [PATCH 33/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index e2678bd..3b90ab3 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,4 +2,4 @@ This file is part of the MQT QAO library released under the MIT license. See README.md or go to https://github.com/cda-tum/mqt-predictor for more information. -""" \ No newline at end of file +""" From 8dc99dbc5340d55a6b8698cabf0993d7715880f7 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Fri, 31 May 2024 14:35:24 +0200 Subject: [PATCH 34/89] update qiskit version --- tests/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index e2678bd..3b90ab3 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,4 +2,4 @@ This file is part of the MQT QAO library released under the MIT license. See README.md or go to https://github.com/cda-tum/mqt-predictor for more information. -""" \ No newline at end of file +""" From cd10880f58d48684377c880942db763880201e20 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Fri, 31 May 2024 14:36:32 +0200 Subject: [PATCH 35/89] update qiskit version --- tests/test_evaluation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index ca42fe5..8f6a757 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -1526,7 +1526,6 @@ def test_qaoa_solver_qubo_basic() -> None: else: assert solution - def test_vqe_solver_qubo_basic() -> None: """Test for the problem constructions""" variables = Variables() From e8f91d90b7196d89fb1b27e6330dfd749de14270 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 12:39:02 +0000 Subject: [PATCH 36/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_evaluation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 8f6a757..ca42fe5 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -1526,6 +1526,7 @@ def test_qaoa_solver_qubo_basic() -> None: else: assert solution + def test_vqe_solver_qubo_basic() -> None: """Test for the problem constructions""" variables = Variables() From c42a2a456c3354c76e506ae61af167d54d67da92 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Fri, 31 May 2024 17:02:14 +0200 Subject: [PATCH 37/89] update qiskit version --- src/mqt/qao/objectivefunction.py | 245 +++++++++++++++------------- src/mqt/qao/solvers.py | 13 +- src/mqt/qao/variables.py | 268 ++++++++++++------------------- tests/test_evaluation.py | 1 + 4 files changed, 251 insertions(+), 276 deletions(-) diff --git a/src/mqt/qao/objectivefunction.py b/src/mqt/qao/objectivefunction.py index 6e79c7c..f064fe0 100644 --- a/src/mqt/qao/objectivefunction.py +++ b/src/mqt/qao/objectivefunction.py @@ -34,6 +34,112 @@ def add_objective_function(self, objective_function: Expr, minimization: bool = objective_function = -objective_function self.objective_functions.append((cast(Expr, expand(objective_function).evalf()), weight)) + @staticmethod + def rewrite_powers(powers: list[str], var: Variables, to_add: float) -> float | bool: + temp = 0.0 + try: + power = int(powers[1]) + except TypeError: + print("Expression not supported\n") + return False + key = powers[0] + if key not in var.binary_variables_name_weight: + print("Expression not supported\n") + return False + if isinstance(var.binary_variables_name_weight[key], list): + encoding = var.binary_variables_name_weight[key][0] + if encoding == "dictionary": + for elem in var.binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] ** power + elif len(elem) == 3: + t = t * elem[1] ** power + elem[2] ** power + temp += t + else: + for elem in var.binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + temp **= power + elif isinstance(var.binary_variables_name_weight[key], tuple): + t = 1.0 + t *= var.binary_variables_name_weight[key][0] + if len(var.binary_variables_name_weight[key]) == 2: + t *= (var.binary_variables_name_weight[key][1]) ** power + elif len(var.binary_variables_name_weight[key]) == 3: + t = (t * var.binary_variables_name_weight[key][1] + var.binary_variables_name_weight[key][2]) ** power + temp += t + else: + temp = var.binary_variables_name_weight[key] + to_add *= temp + + return to_add + + @staticmethod + def rewrite_no_power(poly_field: str, var: Variables, to_add: float) -> float | bool: + temp = 0.0 + key = poly_field + if key not in var.binary_variables_name_weight: + try: + to_add *= float(key) + except TypeError: + print("Expression not supported\n") + return False + else: + if isinstance(var.binary_variables_name_weight[key], list): + for elem in var.binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + elif isinstance(var.binary_variables_name_weight[key], tuple): + t = 1.0 + t *= var.binary_variables_name_weight[key][0] + if len(var.binary_variables_name_weight[key]) == 2: + t *= var.binary_variables_name_weight[key][1] + elif len(var.binary_variables_name_weight[key]) == 3: + t = t * var.binary_variables_name_weight[key][1] + var.binary_variables_name_weight[key][2] + temp += t + else: + temp += var.binary_variables_name_weight[key] + to_add *= temp + return to_add + + def rewrite_elem(self, field: str, var: Variables, func: float, sign: str) -> float | bool: + poly_fields = field.split("*") + to_add = 1.0 + for poly_field in poly_fields: + powers = poly_field.split("^") + + if len(powers) == 2: + t = self.rewrite_powers(powers, var, to_add) + if isinstance(t, bool): + return False + to_add = t + else: + t = self.rewrite_no_power(poly_field, var, to_add) + if isinstance(t, bool): + return False + to_add = t + if sign == "+": + func += to_add + else: + func -= to_add + + return func + def rewrite_cost_functions(self, pubo: PUBO, var: Variables) -> PUBO | bool: """function for rewriting the cost functions according with the variable structure @@ -54,101 +160,40 @@ def rewrite_cost_functions(self, pubo: PUBO, var: Variables) -> PUBO | bool: sign = "+" for field in fields: if field not in {"+", "-"}: - poly_fields = field.split("*") - to_add = 1.0 - for poly_field in poly_fields: - powers = poly_field.split("^") - temp = 0.0 - if len(powers) == 2: - try: - power = int(powers[1]) - except TypeError: - print("Expression not supported\n") - return False - key = powers[0] - if key not in var.binary_variables_name_weight: - print("Expression not supported\n") - return False - if isinstance(var.binary_variables_name_weight[key], list): - encoding = var.binary_variables_name_weight[key][0] - if encoding == "dictionary": - for elem in var.binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] ** power - elif len(elem) == 3: - t = t * elem[1] ** power + elem[2] ** power - temp += t - else: - for elem in var.binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - temp **= power - elif isinstance(var.binary_variables_name_weight[key], tuple): - t = 1.0 - t *= var.binary_variables_name_weight[key][0] - if len(var.binary_variables_name_weight[key]) == 2: - t *= (var.binary_variables_name_weight[key][1]) ** power - elif len(var.binary_variables_name_weight[key]) == 3: - t = ( - t * var.binary_variables_name_weight[key][1] - + var.binary_variables_name_weight[key][2] - ) ** power - temp += t - else: - temp = var.binary_variables_name_weight[key] - to_add *= temp - else: - key = poly_field - if key not in var.binary_variables_name_weight: - try: - to_add *= float(key) - except TypeError: - print("Expression not supported\n") - return False - else: - if isinstance(var.binary_variables_name_weight[key], list): - for elem in var.binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - elif isinstance(var.binary_variables_name_weight[key], tuple): - t = 1.0 - t *= var.binary_variables_name_weight[key][0] - if len(var.binary_variables_name_weight[key]) == 2: - t *= var.binary_variables_name_weight[key][1] - elif len(var.binary_variables_name_weight[key]) == 3: - t = ( - t * var.binary_variables_name_weight[key][1] - + var.binary_variables_name_weight[key][2] - ) - temp += t - else: - temp += var.binary_variables_name_weight[key] - to_add *= temp - - if sign == "+": - func += to_add - else: - func -= to_add + t = self.rewrite_elem(field, var, func, sign) + if isinstance(t, bool): + return False + func = t else: sign = field pubo += func * obj[1] return pubo + @staticmethod + def var_list_substitution(var: str, solution: dict[str, Any], variables: Variables, temp_expression: Expr) -> Expr: + for i in range(len(solution[var])): + if isinstance(solution[var][i], list): + for j in range(len(solution[var][i])): + if isinstance(solution[var][i][j], list): + for k in range(len(solution[var][i][j])): + temp_expression = temp_expression.subs({ + variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][k] + }) + else: + temp_expression = temp_expression.subs({ + variables.variables_dict[var][i][j].symbol: solution[var][i][j] + }) + else: + temp_expression = temp_expression.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + return temp_expression + + def var_substitution(self, var: str, solution: dict[str, Any], variables: Variables, temp_expression: Expr) -> Expr: + if isinstance(solution[var], float): + temp_expression = temp_expression.subs({variables.variables_dict[var].symbol: solution[var]}) + elif isinstance(solution[var], list): + temp_expression = self.var_list_substitution(var, solution, variables, temp_expression) + return temp_expression + def substitute_values(self, solution: dict[str, Any], variables: Variables) -> dict[str, float] | bool: """function for substituting solutions into the cost functions expressions @@ -166,25 +211,7 @@ def substitute_values(self, solution: dict[str, Any], variables: Variables) -> d temp_expression = obj[0] for var in solution: if var in variables.variables_dict: - if isinstance(solution[var], float): - temp_expression = temp_expression.subs({variables.variables_dict[var].symbol: solution[var]}) - elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - temp_expression = temp_expression.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][k] - }) - else: - temp_expression = temp_expression.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - temp_expression = temp_expression.subs({ - variables.variables_dict[var][i].symbol: solution[var][i] - }) + temp_expression = self.var_substitution(var, solution, variables, temp_expression) try: objective_functions_values[str(obj[0])] = float(temp_expression) except ValueError: diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index c4d5ad1..1aa79f5 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -524,7 +524,7 @@ def solve_qaoa_qubo( problem: Problem, auto_setting: bool = False, num_runs: int = 10, - optimizer: Optimizer = COBYLA(), + optimizer: Optimizer | None = None, reps: int = 1, initial_state: QuantumCircuit | None = None, mixer: QuantumCircuit = None, @@ -587,6 +587,9 @@ def solve_qaoa_qubo( initial_state = QuantumCircuit(var_num) for _idx in range(var_num): initial_state.h(_idx) + + if optimizer is None: + optimizer = COBYLA() qaoa_mes = QAOA( sampler=Sampler(), optimizer=optimizer, @@ -664,7 +667,7 @@ def solve_vqe_qubo( problem: Problem, auto_setting: bool = False, num_runs: int = 10, - optimizer: Optimizer = COBYLA(), + optimizer: Optimizer | None = None, ansatz: QuantumCircuit | None = None, initial_point: np.ndarray[Any, Any] | None = None, aggregation: float | Callable[[list[float]], float] | None = None, @@ -714,6 +717,9 @@ def solve_vqe_qubo( if auto_setting or ansatz is None: ansatz = TwoLocal(num_qubits=len(self.qubo.variables), rotation_blocks="ry", entanglement_blocks="cz") + if optimizer is None: + optimizer = COBYLA() + vqe_mes = SamplingVQE( sampler=Sampler(), optimizer=optimizer, @@ -786,7 +792,8 @@ def solve_vqe_qubo( def get_lambda_updates(self) -> int: return self._number_of_lambda_update - def _from_qubovert_to_qiskit_model(self, qubo: QUBO) -> QuadraticProgram: + @staticmethod + def _from_qubovert_to_qiskit_model(qubo: QUBO) -> QuadraticProgram: """function for converting the qubovert formulation into the qiskit quadratic model one Keyword arguments: diff --git a/src/mqt/qao/variables.py b/src/mqt/qao/variables.py index e89290a..b21f75d 100644 --- a/src/mqt/qao/variables.py +++ b/src/mqt/qao/variables.py @@ -437,6 +437,102 @@ def _variable_binarization( return constraints, i + def conv_var(self, v1: Variable, solution: dict[str, float]) -> float | bool: + temp = 0.0 + if isinstance(self.binary_variables_name_weight[v1.name], list): + for el in self.binary_variables_name_weight[v1.name]: + if not isinstance(el, str): + key = next(iter(el[0].variables)) + if key not in solution: + print("The variable is not found\n") + return False + if solution[key] == 1: + temp += el[1] if len(el) > 1 else 1 + if len(el) == 3: + temp += el[2] + elif next(iter(self.binary_variables_name_weight[v1.name][0].variables)) in solution: + key = next(iter(self.binary_variables_name_weight[v1.name][0].variables)) + if solution[key] == 1: + temp += ( + self.binary_variables_name_weight[v1.name][1] + if len(self.binary_variables_name_weight[v1.name]) > 1 + else 1 + ) + if len(self.binary_variables_name_weight[v1.name]) == 3: + temp += self.binary_variables_name_weight[v1.name][2] + else: + print("The variable is not found\n") + return False + + return temp + + def conv_list(self, v1: list[Variable], solution: dict[str, float]) -> list[float] | bool: + nested_temp_list = [] + for v2 in v1: + if not isinstance(v2, list) and v2.name in self.binary_variables_name_weight: + temp = self.conv_var(v2, solution) + if isinstance(temp, bool): + return False + nested_temp_list.append(temp) + return nested_temp_list + + def convert_solution_var( + self, converted_solution: dict[str, Any], var: str, solution: dict[str, float] + ) -> dict[str, Any] | bool: + """function for converting a solution coming from simulated annealing""" + converted_solution[var] = [] + for j, v in enumerate(self.variables_dict[var]): + if isinstance(v, list): + converted_solution[var].append([]) + for v1 in v: + if not isinstance(v1, list) and v1.name in self.binary_variables_name_weight: + temp = self.conv_var(v1, solution) + if isinstance(temp, bool): + return False + converted_solution[var][j].append(temp) + elif isinstance(v1, list): + nested_temp_list = self.conv_list(v1, solution) + if isinstance(nested_temp_list, bool): + return False + converted_solution[var][j].append(nested_temp_list) + elif v.name in self.binary_variables_name_weight: + temp = self.conv_var(v, solution) + if isinstance(temp, bool): + return False + converted_solution[var].append(temp) + return converted_solution + + def converted_solution_single_var( + self, converted_solution: dict[str, Any], var: str, solution: dict[str, float] + ) -> dict[str, Any] | bool: + converted_solution[var] = 0.0 + if var not in self.binary_variables_name_weight: + print("The variable is not found\n") + return False + if isinstance(self.binary_variables_name_weight[var], list): + for el in self.binary_variables_name_weight[var]: + if not isinstance(el, str): + key = next(iter(el[0].variables)) + if key not in solution: + print("The variable is not found\n") + return False + if solution[key] == 1: + converted_solution[var] += el[1] if len(el) > 1 else 1 + if len(el) == 3: + converted_solution[var] += el[2] + elif next(iter(self.binary_variables_name_weight[var][0].variables)) in solution: + key = next(iter(self.binary_variables_name_weight[var][0].variables)) + if solution[key] == 1: + converted_solution[var] += ( + self.binary_variables_name_weight[var][1] if len(self.binary_variables_name_weight[var]) > 1 else 1 + ) + if len(self.binary_variables_name_weight[var]) == 3: + converted_solution[var] += self.binary_variables_name_weight[var][2] + else: + print("The variable is not found\n") + return False + return converted_solution + def convert_simulated_annealing_solution(self, solution: dict[str, float]) -> dict[str, Any] | bool: """function for converting a solution coming from simulated annealing @@ -449,172 +545,16 @@ def convert_simulated_annealing_solution(self, solution: dict[str, float]) -> di """ converted_solution: dict[str, Any] = {} for var in self.variables_dict: - if isinstance(self.variables_dict[var], Variable): - converted_solution[var] = 0.0 - if var in self.binary_variables_name_weight: - if isinstance(self.binary_variables_name_weight[var], list): - for el in self.binary_variables_name_weight[var]: - if ( - not isinstance(el, str) - and next(iter(el[0].variables)) in solution - and solution[next(iter(el[0].variables))] == 1 - ): - if len(el) > 1: - converted_solution[var] += el[1] - else: - converted_solution[var] += 1 - if not isinstance(el, str) and next(iter(el[0].variables)) in solution and len(el) == 3: - converted_solution[var] += el[2] - if not isinstance(el, str) and next(iter(el[0].variables)) not in solution: - print("The variable is not found\n") - return False - else: - if ( - next(iter(self.binary_variables_name_weight[var][0].variables)) in solution - and solution[next(iter(self.binary_variables_name_weight[var][0].variables))] == 1 - ): - if len(self.binary_variables_name_weight[var]) > 1: - converted_solution[var] += self.binary_variables_name_weight[var][1] - else: - converted_solution[var] += 1 - - if ( - next(iter(self.binary_variables_name_weight[var][0].variables)) in solution - and len(self.binary_variables_name_weight[var]) == 3 - ): - converted_solution[var] += self.binary_variables_name_weight[var][2] - if next(iter(self.binary_variables_name_weight[var][0].variables)) not in solution: - print("The variable is not found\n") - return False - - else: - print("The variable is not found\n") + if not isinstance(self.variables_dict[var], Variable): + temp = self.convert_solution_var(converted_solution, var, solution) + if isinstance(temp, bool): return False + converted_solution = temp else: - converted_solution[var] = [] - j = 0 - for v in self.variables_dict[var]: - if not isinstance(v, list) and v.name in self.binary_variables_name_weight: - temp = 0.0 - if isinstance(self.binary_variables_name_weight[v.name], list): - for el in self.binary_variables_name_weight[v.name]: - if not isinstance(el, str): - if ( - next(iter(el[0].variables)) in solution - and solution[next(iter(el[0].variables))] == 1 - ): - if len(el) > 1: - temp += el[1] - else: - temp += 1 - if next(iter(el[0].variables)) in solution and len(el) == 3: - temp += el[2] - if next(iter(el[0].variables)) not in solution: - print("The variable is not found\n") - return False - elif next(iter(self.binary_variables_name_weight[v.name][0].variables)) in solution: - if ( - solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 - ) and len(self.binary_variables_name_weight[v.name]) > 1: - temp += self.binary_variables_name_weight[v.name][1] - if ( - solution[next(iter(self.binary_variables_name_weight[v.name][0].variables))] == 1 - ) and len(self.binary_variables_name_weight[v.name]) == 1: - temp += 1 - if len(self.binary_variables_name_weight[v.name]) == 3: - temp += self.binary_variables_name_weight[v.name][2] - else: - print("The variable is not found\n") - return False - converted_solution[var].append(temp) - elif isinstance(v, list): - converted_solution[var].append([]) - k = 0 - for v1 in v: - if not isinstance(v1, list): - if v1.name in self.binary_variables_name_weight: - temp = 0.0 - if isinstance(self.binary_variables_name_weight[v1.name], list): - for el in self.binary_variables_name_weight[v1.name]: - if not isinstance(el, str): - if ( - next(iter(el[0].variables)) in solution - and solution[next(iter(el[0].variables))] == 1 - ): - if len(el) > 1: - temp += el[1] - else: - temp += 1 - if next(iter(el[0].variables)) in solution and len(el) == 3: - temp += el[2] - if next(iter(el[0].variables)) not in solution: - print("The variable is not found\n") - return False - elif ( - next(iter(self.binary_variables_name_weight[v1.name][0].variables)) in solution - ): - if ( - solution[ - next(iter(self.binary_variables_name_weight[v1.name][0].variables)) - ] - == 1 - ) and len(self.binary_variables_name_weight[v1.name]) > 0: - if len(self.binary_variables_name_weight[v1.name]) > 1: - temp += self.binary_variables_name_weight[v1.name][1] - else: - temp += 1 - if len(self.binary_variables_name_weight[v1.name]) == 3: - temp += self.binary_variables_name_weight[v1.name][2] - else: - print("The variable is not found\n") - return False - - converted_solution[var][j].append(temp) - else: - converted_solution[var][j].append([]) - for v2 in v: - if not isinstance(v2, list) and v2.name in self.binary_variables_name_weight: - temp = 0.0 - if isinstance(self.binary_variables_name_weight[v2.name], list): - for el in self.binary_variables_name_weight[v2.name]: - if ( - not isinstance(el, str) - and next(iter(el[0].variables)) in solution - and solution[next(iter(el[0].variables))] == 1 - ): - if len(el) > 1: - temp += el[1] - else: - temp += 1 - if ( - not isinstance(el, str) - and next(iter(el[0].variables)) in solution - and len(el) == 3 - ): - temp += el[2] - if next(iter(el[0].variables)) not in solution: - print("The variable is not found\n") - return False - elif ( - next(iter(self.binary_variables_name_weight[v2.name][0].variables)) - in solution - ): - if ( - solution[ - next(iter(self.binary_variables_name_weight[v2.name][0].variables)) - ] - == 1 - ) and len(self.binary_variables_name_weight[v2.name]) > 1: - temp += self.binary_variables_name_weight[v2.name][1] - if len(self.binary_variables_name_weight[v2.name]) == 3: - temp += self.binary_variables_name_weight[v2.name][2] - else: - print("The variable is not found\n") - return False - converted_solution[var][j][k].append(temp) - k += 1 - j += 1 - + temp = self.converted_solution_single_var(converted_solution, var, solution) + if isinstance(temp, bool): + return False + converted_solution = temp return converted_solution diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 8f6a757..ca42fe5 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -1526,6 +1526,7 @@ def test_qaoa_solver_qubo_basic() -> None: else: assert solution + def test_vqe_solver_qubo_basic() -> None: """Test for the problem constructions""" variables = Variables() From 07e1f260175b399a81a23a64333cb632e99e4da2 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Fri, 31 May 2024 17:12:46 +0200 Subject: [PATCH 38/89] update qiskit version --- src/mqt/qao/constraints.py | 90 +++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index 4dd6794..65c50ec 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -2140,7 +2140,8 @@ def _convert_expression_prec( sign = field return func, min_precision - def _convert_expression_logic(self, expr: Expr, binary_variables_name_weight: dict[str, Any]) -> boolean_var | bool: + @staticmethod + def _convert_expression_logic(expr: Expr, binary_variables_name_weight: dict[str, Any]) -> boolean_var | bool: """function for translating an expression in the problem variable in case of logic constraints Keyword arguments: @@ -2188,7 +2189,52 @@ def _min_max_const_estimation(exp: PUBO) -> tuple[float, float, float]: return min_val, max_val, const @staticmethod - def _expression_to_hamiltonian(exp: Expr, binary_variables_name_weight_val: list[Any]) -> PUBO: + def _expression_to_hamiltonian_power( + powers: list[str], binary_variables_name_weight_val: list[Any], to_add: float + ) -> float | bool: + try: + power = int(powers[1]) + except TypeError: + print("Expression not supported\n") + return False + key = powers[0] + for elm in binary_variables_name_weight_val: + if isinstance(elm, list): + for el in elm: + if not isinstance(el, str) and key == (next(iter(el[0].variables))): + to_add *= el[0] ** power + break + elif not isinstance(elm, str) and key == next(iter(elm[0].variables)): + to_add *= elm[0] ** power + break + return to_add + + @staticmethod + def _expression_to_hamiltonian_no_power( + poly_field: str, binary_variables_name_weight_val: list[Any], to_add: float + ) -> float: + key = poly_field + is_float = False + try: + temp = float(key) + except ValueError: + pass + else: + to_add *= temp + is_float = True + + if not is_float: + for elm in binary_variables_name_weight_val: + if isinstance(elm, list): + for el in elm: + if not isinstance(el, str) and key == next(iter(el[0].variables)): + to_add *= el[0] + elif not isinstance(elm, str) and key == next(iter(elm[0].variables)): + to_add *= elm[0] + + return to_add + + def _expression_to_hamiltonian(self, exp: Expr, binary_variables_name_weight_val: list[Any]) -> PUBO: """function for translating an expression in the problem variable into an Hamiltonian when is directly written with the inside binary variables Keyword arguments: @@ -2208,40 +2254,14 @@ def _expression_to_hamiltonian(exp: Expr, binary_variables_name_weight_val: list for poly_field in poly_fields: powers = poly_field.split("^") if len(powers) == 2: - try: - power = int(powers[1]) - except TypeError: - print("Expression not supported\n") - return False - key = powers[0] - for elm in binary_variables_name_weight_val: - if isinstance(elm, list): - for el in elm: - if not isinstance(el, str) and key == (next(iter(el[0].variables))): - to_add *= el[0] ** power - break - elif not isinstance(elm, str) and key == next(iter(elm[0].variables)): - to_add *= elm[0] ** power - break + t = self._expression_to_hamiltonian_power(powers, binary_variables_name_weight_val, to_add) + if not isinstance(t, bool): + to_add = t else: - key = poly_field - is_float = False - try: - temp = float(key) - except ValueError: - pass - else: - to_add *= temp - is_float = True - - if not is_float: - for elm in binary_variables_name_weight_val: - if isinstance(elm, list): - for el in elm: - if not isinstance(el, str) and key == next(iter(el[0].variables)): - to_add *= el[0] - elif not isinstance(elm, str) and key == next(iter(elm[0].variables)): - to_add *= elm[0] + to_add = self._expression_to_hamiltonian_no_power( + poly_field, binary_variables_name_weight_val, to_add + ) + if sign == "+": hamiltonian += to_add else: From 56feffcbd198f0a7601c47c66ad4cdc518c1e53c Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 09:57:20 +0200 Subject: [PATCH 39/89] update qiskit version --- src/mqt/qao/constraints.py | 1128 ++++++++++++++++-------------------- 1 file changed, 501 insertions(+), 627 deletions(-) diff --git a/src/mqt/qao/constraints.py b/src/mqt/qao/constraints.py index 65c50ec..54417e8 100644 --- a/src/mqt/qao/constraints.py +++ b/src/mqt/qao/constraints.py @@ -7,7 +7,7 @@ # for managing symbols from sympy import Expr, expand -from .variables import Variables +from .variables import Variable, Variables class Constraints: @@ -218,15 +218,7 @@ def _not_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> print("Wrong constraint format\n") return False - op = [] - for e in el: - for elms in var.binary_variables_name_weight.values(): - if isinstance(elms, list): - for elm in elms: - if not isinstance(elm, str) and e == next(iter(elm[0].variables)): - op.append(elm[0]) # noqa: PERF401 - elif e == next(iter(elms[0].variables)): - op.append(elms[0]) + op = self._logic_constraint(el, var) ret = 2 * op[0] * op[1] - op[0] - op[1] + 1 return ret @@ -251,48 +243,26 @@ def _not_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, + variables, + expr1, + expr2, + var, + expr1_to_sub, + expr2_to_sub, + ) try: return bool(expr1) != bool(expr2) except ValueError: return False - def _not_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _not_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the not constraint penalty function. Keyword arguments: @@ -379,15 +349,7 @@ def _and_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> return False el = [el2[0], el2[1], el[1]] - op = [] - for e in el: - for elms in var.binary_variables_name_weight.values(): - if isinstance(elms, list): - for elm in elms: - if not isinstance(elm, str) and e == next(iter(elm[0].variables)): - op.append(elm[0]) # noqa: PERF401 - elif e == next(iter(elms[0].variables)): - op.append(elms[0]) + op = self._logic_constraint(el, var) ret = op[0] * op[1] - 2 * (op[0] + op[1]) * op[2] + 3 * op[2] return ret @@ -421,62 +383,27 @@ def _and_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var], + variables.variables_dict[var], + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_list_var( + solution, variables, expr1, expr2, expr3, var, expr1_to_sub, expr2_to_sub, expr3_to_sub + ) try: return bool(expr1) and bool(expr2) == bool(expr3) except ValueError: return False - def _and_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _and_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the and constraint penalty function. Keyword arguments: @@ -578,15 +505,7 @@ def _or_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> return False el = [el2[0], el2[1], el[1]] - op = [] - for e in el: - for elms in var.binary_variables_name_weight.values(): - if isinstance(elms, list): - for elm in elms: - if not isinstance(elm, str) and e == next(iter(elm[0].variables)): - op.append(elm[0]) # noqa: PERF401 - elif e == next(iter(elms[0].variables)): - op.append(elms[0]) + op = self._logic_constraint(el, var) ret = op[0] * op[1] + (op[0] + op[1]) * (1 - 2 * op[2]) + op[2] return ret @@ -619,62 +538,27 @@ def _or_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var], + variables.variables_dict[var], + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_list_var( + solution, variables, expr1, expr2, expr3, var, expr1_to_sub, expr2_to_sub, expr3_to_sub + ) try: return bool(expr1) or bool(expr2) == bool(expr3) except ValueError: return False - def _or_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _or_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the or constraint penalty function. Keyword arguments: @@ -729,6 +613,19 @@ def _or_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) except ValueError: return False + @staticmethod + def _logic_constraint(el: list[str], var: Variables) -> list[PUBO]: + op = [] + for e in el: + for elms in var.binary_variables_name_weight.values(): + if isinstance(elms, list): + for elm in elms: + if not isinstance(elm, str) and e == next(iter(elm[0].variables)): + op.append(elm[0]) # noqa: PERF401 + elif e == next(iter(elms[0].variables)): + op.append(elms[0]) + return op + def _xor_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> PUBO | bool: """function for writing the xor constraint penalty function. @@ -765,21 +662,83 @@ def _xor_constraint(self, elem: tuple[str, bool, bool, bool], var: Variables) -> print("Wrong constraint format\n") return False el = [el2[0], el2[1], el[1]] - op = [] - for e in el: - for elms in var.binary_variables_name_weight.values(): - if isinstance(elms, list): - for elm in elms: - if not isinstance(elm, str) and e == next(iter(elm[0].variables)): - op.append(elm[0]) # noqa: PERF401 - elif e == next(iter(elms[0].variables)): - op.append(elms[0]) + op = self._logic_constraint(el, var) a = op[0] b = op[1] c = op[2] ret = a + b + c - 2 * a * c - 2 * b * c - 2 * a * b + 4 * a * b * c return ret + @staticmethod + def _constraint_check_three_sub_single_var( + expr1_to_sub: bool, + expr2_to_sub: bool, + expr3_to_sub: bool, + expr1: Expr, + expr2: Expr, + expr3: Expr, + sol_val: float, + variable: Variable, + ) -> tuple[Expr, Expr, Expr]: + if expr1_to_sub: + expr1 = expr1.subs({variable.symbol: sol_val}) + if expr2_to_sub: + expr2 = expr2.subs({variable.symbol: sol_val}) + if expr3_to_sub: + expr3 = expr3.subs({variable.symbol: sol_val}) + return expr1, expr2, expr3 + + def _constraint_check_three_sub_list_var( + self, + solution: dict[str, Any], + variables: Variables, + expr1: Expr, + expr2: Expr, + expr3: Expr, + var: str, + expr1_to_sub: bool, + expr2_to_sub: bool, + expr3_to_sub: bool, + ) -> tuple[Expr, Expr, Expr]: + for i in range(len(solution[var])): + if isinstance(solution[var][i], list): + for j in range(len(solution[var][i])): + if isinstance(solution[var][i][j], list): + for k in range(len(solution[var][i][j])): + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var][i][j][k], + variables.variables_dict[var][i][j][k], + ) + else: + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var][i][j], + variables.variables_dict[var][i][j], + ) + else: + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var][i], + variables.variables_dict[var][i], + ) + return expr1, expr2, expr3 + def _xor_constraint_check(self, constraint: str, variables: Variables, solution: dict[str, Any]) -> bool: """function for checking the xor constraint penalty function. @@ -809,62 +768,27 @@ def _xor_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr3_to_sub, + expr1, + expr2, + expr3, + solution[var], + variables.variables_dict[var], + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr3_to_sub: - expr3 = expr3.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr3_to_sub: - expr3 = expr3.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2, expr3 = self._constraint_check_three_sub_list_var( + solution, variables, expr1, expr2, expr3, var, expr1_to_sub, expr2_to_sub, expr3_to_sub + ) try: return bool(expr1) ^ bool(expr2) == bool(expr3) except ValueError: return False - def _xor_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _xor_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the xor constraint penalty function. Keyword arguments: @@ -919,6 +843,59 @@ def _xor_constraint_check_no_sub(self, constraint: str, solution: dict[str, int] except ValueError: return False + @staticmethod + def _constraint_check_sub_single_var( + expr1_to_sub: bool, expr2_to_sub: bool, expr1: Expr, expr2: Expr, sol_val: float, variable: Variable + ) -> tuple[Expr, Expr]: + if expr1_to_sub: + expr1 = expr1.subs({variable.symbol: sol_val}) + if expr2_to_sub: + expr2 = expr2.subs({variable.symbol: sol_val}) + return expr1, expr2 + + def _constraint_check_sub_list_var( + self, + solution: dict[str, Any], + variables: Variables, + expr1: Expr, + expr2: Expr, + var: str, + expr1_to_sub: bool, + expr2_to_sub: bool, + ) -> tuple[Expr, Expr]: + for i in range(len(solution[var])): + if isinstance(solution[var][i], list): + for j in range(len(solution[var][i])): + if isinstance(solution[var][i][j], list): + for k in range(len(solution[var][i][j])): + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr1, + expr2, + solution[var][i][j][k], + variables.variables_dict[var][i][j][k], + ) + else: + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr1, + expr2, + solution[var][i][j], + variables.variables_dict[var][i][j], + ) + else: + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, + expr2_to_sub, + expr1, + expr2, + solution[var][i], + variables.variables_dict[var][i], + ) + return expr1, expr2 + def _greq_constraint( self, elem: tuple[str, bool, bool, bool], var: Variables, aux: Variables, i: int, j: int ) -> tuple[ @@ -1034,48 +1011,20 @@ def _greq_constraint_check(self, constraint: str, variables: Variables, solution for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, variables, expr1, expr2, var, expr1_to_sub, expr2_to_sub + ) try: return float(expr1) >= float(expr2) except ValueError: return False - def _greq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _greq_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the grater equal constraint penalty function. Keyword arguments: @@ -1229,48 +1178,20 @@ def _lteq_constraint_check(self, constraint: str, variables: Variables, solution for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, variables, expr1, expr2, var, expr1_to_sub, expr2_to_sub + ) try: return float(expr1) <= float(expr2) except ValueError: return False - def _lteq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _lteq_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the less equal constraint penalty function. Keyword arguments: @@ -1434,48 +1355,20 @@ def _grt_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, variables, expr1, expr2, var, expr1_to_sub, expr2_to_sub + ) try: return float(expr1) > float(expr2) except ValueError: return False - def _grt_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _grt_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the greater equal constraint penalty function. Keyword arguments: @@ -1642,48 +1535,20 @@ def _lt_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, variables, expr1, expr2, var, expr1_to_sub, expr2_to_sub + ) try: return float(expr1) < float(expr2) except ValueError: return False - def _lt_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _lt_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the less equal constraint penalty function. Keyword arguments: @@ -1773,48 +1638,20 @@ def _eq_constraint_check(self, constraint: str, variables: Variables, solution: for var in solution: if var in variables.variables_dict: if isinstance(solution[var], float): - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var].symbol: solution[var]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var].symbol: solution[var]}) + expr1, expr2 = self._constraint_check_sub_single_var( + expr1_to_sub, expr2_to_sub, expr1, expr2, solution[var], variables.variables_dict[var] + ) elif isinstance(solution[var], list): - for i in range(len(solution[var])): - if isinstance(solution[var][i], list): - for j in range(len(solution[var][i])): - if isinstance(solution[var][i][j], list): - for k in range(len(solution[var][i][j])): - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j][k].symbol: solution[var][i][j][ - k - ] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - if expr2_to_sub: - expr2 = expr2.subs({ - variables.variables_dict[var][i][j].symbol: solution[var][i][j] - }) - else: - if expr1_to_sub: - expr1 = expr1.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) - if expr2_to_sub: - expr2 = expr2.subs({variables.variables_dict[var][i].symbol: solution[var][i]}) + expr1, expr2 = self._constraint_check_sub_list_var( + solution, variables, expr1, expr2, var, expr1_to_sub, expr2_to_sub + ) try: return float(expr1) == float(expr2) except ValueError: return False - def _eq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) -> bool: + @staticmethod + def _eq_constraint_check_no_sub(constraint: str, solution: dict[str, int]) -> bool: """function for checking the equality constraint penalty function. Keyword arguments: @@ -1854,6 +1691,88 @@ def _eq_constraint_check_no_sub(self, constraint: str, solution: dict[str, int]) except ValueError: return False + @staticmethod + def _convert_expression_power( + powers: list[str], binary_variables_name_weight: dict[str, Any], to_add: float + ) -> float | bool: + temp = 0.0 + try: + power = int(powers[1]) + except TypeError: + print("Expression not supported\n") + return False + key = powers[0] + if key not in binary_variables_name_weight: + print("Expression not supported\n") + return False + if isinstance(binary_variables_name_weight[key], list): + encoding = binary_variables_name_weight[key][0] + if encoding == "dictionary": + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] ** power + elif len(elem) == 3: + t = t * elem[1] ** power + elem[2] ** power + temp += t + else: + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + temp **= power + else: + t = 1.0 + t *= binary_variables_name_weight[key][0] + if len(binary_variables_name_weight[key]) == 2: + t *= (binary_variables_name_weight[key][1]) ** power + elif len(binary_variables_name_weight[key]) == 3: + t = (t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2]) ** power + temp += t + to_add *= temp + return to_add + + @staticmethod + def _convert_expression_no_power( + poly_field: str, binary_variables_name_weight: dict[str, Any], to_add: float + ) -> float | bool: + temp = 0.0 + key = poly_field + if key not in binary_variables_name_weight: + try: + to_add *= float(key) + except TypeError: + print("Expression not supported\n") + return False + else: + if isinstance(binary_variables_name_weight[key], list): + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + else: + t = 1.0 + t *= binary_variables_name_weight[key][0] + if len(binary_variables_name_weight[key]) == 2: + t *= binary_variables_name_weight[key][1] + elif len(binary_variables_name_weight[key]) == 3: + t = t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] + temp += t + to_add *= temp + return to_add + def _convert_expression(self, expr: Expr, binary_variables_name_weight: dict[str, Any]) -> PUBO | bool: """function for translating an expression in the problem variable @@ -1873,79 +1792,14 @@ def _convert_expression(self, expr: Expr, binary_variables_name_weight: dict[str to_add = 1.0 for poly_field in poly_fields: powers = poly_field.split("^") - temp = 0.0 if len(powers) == 2: - try: - power = int(powers[1]) - except TypeError: - print("Expression not supported\n") - return False - key = powers[0] - if key not in binary_variables_name_weight: - print("Expression not supported\n") - return False - if isinstance(binary_variables_name_weight[key], list): - encoding = binary_variables_name_weight[key][0] - if encoding == "dictionary": - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] ** power - elif len(elem) == 3: - t = t * elem[1] ** power + elem[2] ** power - temp += t - else: - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - temp **= power - else: - t = 1.0 - t *= binary_variables_name_weight[key][0] - if len(binary_variables_name_weight[key]) == 2: - t *= (binary_variables_name_weight[key][1]) ** power - elif len(binary_variables_name_weight[key]) == 3: - t = ( - t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] - ) ** power - temp += t - to_add *= temp + ret = self._convert_expression_power(powers, binary_variables_name_weight, to_add) else: - key = poly_field - if key not in binary_variables_name_weight: - try: - to_add *= float(key) - except TypeError: - print("Expression not supported\n") - return False - else: - if isinstance(binary_variables_name_weight[key], list): - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - else: - t = 1.0 - t *= binary_variables_name_weight[key][0] - if len(binary_variables_name_weight[key]) == 2: - t *= binary_variables_name_weight[key][1] - elif len(binary_variables_name_weight[key]) == 3: - t = t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] - temp += t - to_add *= temp + ret = self._convert_expression_no_power(poly_field, binary_variables_name_weight, to_add) + + if isinstance(ret, bool): + return False + to_add = ret if sign == "+": func += to_add @@ -1955,6 +1809,167 @@ def _convert_expression(self, expr: Expr, binary_variables_name_weight: dict[str sign = field return func + @staticmethod + def _convert_expression_prec_power( + powers: list[str], + binary_variables_name_weight: dict[str, Any], + variables_dict: dict[str, Any], + to_add: float, + min_precision: float, + ) -> tuple[float, float] | bool: + temp = 0.0 + try: + power = int(powers[1]) + except TypeError: + print("Expression not supported\n") + return False + key = powers[0] + if key not in binary_variables_name_weight: + print("Expression not supported\n") + return False + if isinstance(binary_variables_name_weight[key], list): + encoding = binary_variables_name_weight[key][0] + if encoding == "dictionary": + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] ** power + elif len(elem) == 3: + t = t * elem[1] ** power + elem[2] ** power + temp += t + else: + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + temp **= power + else: + t = 1.0 + t *= binary_variables_name_weight[key][0] + if len(binary_variables_name_weight[key]) == 2: + t *= (binary_variables_name_weight[key][1]) ** power + elif len(binary_variables_name_weight[key]) == 3: + t = (t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2]) ** power + temp += t + to_add *= temp + name = key.split("_") + if len(name) == 1: + if variables_dict[name[0]].type == "c" and min_precision > variables_dict[name[0]].precision: + min_precision = variables_dict[name[0]].precision + elif ( + len(name) == 2 + and name[1].isnumeric() + and name[0] in variables_dict + and variables_dict[name[0]][int(name[1])].type == "c" + ): + min_precision = min(min_precision, variables_dict[name[0]][int(name[1])].precision) + elif ( + len(name) == 3 + and name[1].isnumeric() + and name[2].isnumeric() + and name[0] in variables_dict + and variables_dict[name[0]][int(name[1])][int(name[2])].type == "c" + ): + min_precision = min(min_precision, variables_dict[name[0]][int(name[1])][int(name[2])].precision) + elif ( + len(name) == 4 + and name[1].isnumeric() + and name[2].isnumeric() + and name[3].isnumeric() + and name[0] in variables_dict + and variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].type == "c" + and min_precision > variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision + ): + min_precision = variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision + elif ( + name is variables_dict.keys() + and variables_dict[name[0]].type == "c" + and min_precision > variables_dict[name[0]].precision + ): + min_precision = variables_dict[name[0]].precision + + return to_add, min_precision + + @staticmethod + def _convert_expression_prec_no_power( + poly_field: str, + binary_variables_name_weight: dict[str, Any], + variables_dict: dict[str, Any], + to_add: float, + min_precision: float, + ) -> tuple[float, float] | bool: + temp = 0.0 + key = poly_field + if key not in binary_variables_name_weight: + try: + to_add *= float(key) + except ValueError: + print("Expression not supported\n") + return False + else: + if isinstance(binary_variables_name_weight[key], list): + for elem in binary_variables_name_weight[key]: + if not isinstance(elem, str): + t = 1.0 + t *= elem[0] + if len(elem) == 2: + t *= elem[1] + elif len(elem) == 3: + t = t * elem[1] + elem[2] + temp += t + else: + t = 1.0 + t *= binary_variables_name_weight[key][0] + if len(binary_variables_name_weight[key]) == 2: + t *= binary_variables_name_weight[key][1] + elif len(binary_variables_name_weight[key]) == 3: + t = t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] + temp += t + to_add *= temp + name = key.split("_") + if len(name) == 1 and variables_dict[name[0]].type == "c": + min_precision = min(min_precision, variables_dict[name[0]].precision) + elif ( + len(name) == 2 + and name[1].isnumeric() + and name[0] in variables_dict + and variables_dict[name[0]][int(name[1])].type == "c" + and min_precision > variables_dict[name[0]][int(name[1])].precision + ): + min_precision = variables_dict[name[0]][int(name[1])].precision + elif len(name) == 3 and name[1].isnumeric() and name[2].isnumeric() and name[0] in variables_dict: + if ( + variables_dict[name[0]][int(name[1])][int(name[2])].type == "c" + and min_precision > variables_dict[name[0]][int(name[1])][int(name[2])].precision + ): + min_precision = variables_dict[name[0]][int(name[1])][int(name[2])].precision + elif ( + len(name) == 4 + and name[1].isnumeric() + and name[2].isnumeric() + and name[3].isnumeric() + and name[0] in variables_dict + and variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].type == "c" + ): + min_precision = min( + min_precision, + variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision, + ) + elif ( + name is variables_dict.keys() + and variables_dict[name[0]].type == "c" + and min_precision > variables_dict[name[0]].precision + ): + min_precision = variables_dict[name[0]].precision + return to_add, min_precision + def _convert_expression_prec( self, expr: Expr, binary_variables_name_weight: dict[str, Any], variables_dict: dict[str, Any] ) -> tuple[PUBO, float] | bool: @@ -1970,167 +1985,26 @@ def _convert_expression_prec( fields = str(expr).replace("**", "^").split(" ") func = PUBO() sign = "+" - min_precision = 1 + min_precision = 1.0 for field in fields: if field not in {"+", "-"}: poly_fields = field.split("*") to_add = 1.0 for poly_field in poly_fields: powers = poly_field.split("^") - temp = 0.0 + if len(powers) == 2: - try: - power = int(powers[1]) - except TypeError: - print("Expression not supported\n") - return False - key = powers[0] - if key not in binary_variables_name_weight: - print("Expression not supported\n") - return False - if isinstance(binary_variables_name_weight[key], list): - encoding = binary_variables_name_weight[key][0] - if encoding == "dictionary": - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] ** power - elif len(elem) == 3: - t = t * elem[1] ** power + elem[2] ** power - temp += t - else: - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - temp **= power - else: - t = 1.0 - t *= binary_variables_name_weight[key][0] - if len(binary_variables_name_weight[key]) == 2: - t *= (binary_variables_name_weight[key][1]) ** power - elif len(binary_variables_name_weight[key]) == 3: - t = ( - t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] - ) ** power - temp += t - to_add *= temp - name = key.split("_") - if len(name) == 1: - if ( - variables_dict[name[0]].type == "c" - and min_precision > variables_dict[name[0]].precision - ): - min_precision = variables_dict[name[0]].precision - elif ( - len(name) == 2 - and name[1].isnumeric() - and name[0] in variables_dict - and variables_dict[name[0]][int(name[1])].type == "c" - ): - min_precision = min(min_precision, variables_dict[name[0]][int(name[1])].precision) - elif ( - len(name) == 3 - and name[1].isnumeric() - and name[2].isnumeric() - and name[0] in variables_dict - and variables_dict[name[0]][int(name[1])][int(name[2])].type == "c" - ): - min_precision = min( - min_precision, variables_dict[name[0]][int(name[1])][int(name[2])].precision - ) - elif ( - len(name) == 4 - and name[1].isnumeric() - and name[2].isnumeric() - and name[3].isnumeric() - and name[0] in variables_dict - and variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].type == "c" - and min_precision - > variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision - ): - min_precision = variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision - elif ( - name is variables_dict.keys() - and variables_dict[name[0]].type == "c" - and min_precision > variables_dict[name[0]].precision - ): - min_precision = variables_dict[name[0]].precision + ret = self._convert_expression_prec_power( + powers, binary_variables_name_weight, variables_dict, to_add, min_precision + ) else: - key = poly_field - if key not in binary_variables_name_weight: - try: - to_add *= float(key) - except ValueError: - print("Expression not supported\n") - return False - else: - if isinstance(binary_variables_name_weight[key], list): - for elem in binary_variables_name_weight[key]: - if not isinstance(elem, str): - t = 1.0 - t *= elem[0] - if len(elem) == 2: - t *= elem[1] - elif len(elem) == 3: - t = t * elem[1] + elem[2] - temp += t - else: - t = 1.0 - t *= binary_variables_name_weight[key][0] - if len(binary_variables_name_weight[key]) == 2: - t *= binary_variables_name_weight[key][1] - elif len(binary_variables_name_weight[key]) == 3: - t = t * binary_variables_name_weight[key][1] + binary_variables_name_weight[key][2] - temp += t - to_add *= temp - name = key.split("_") - if len(name) == 1 and variables_dict[name[0]].type == "c": - min_precision = min(min_precision, variables_dict[name[0]].precision) - elif ( - len(name) == 2 - and name[1].isnumeric() - and name[0] in variables_dict - and variables_dict[name[0]][int(name[1])].type == "c" - and min_precision > variables_dict[name[0]][int(name[1])].precision - ): - min_precision = variables_dict[name[0]][int(name[1])].precision - elif ( - len(name) == 3 - and name[1].isnumeric() - and name[2].isnumeric() - and name[0] in variables_dict - ): - if ( - variables_dict[name[0]][int(name[1])][int(name[2])].type == "c" - and min_precision > variables_dict[name[0]][int(name[1])][int(name[2])].precision - ): - min_precision = variables_dict[name[0]][int(name[1])][int(name[2])].precision - elif ( - len(name) == 4 - and name[1].isnumeric() - and name[2].isnumeric() - and name[3].isnumeric() - and name[0] in variables_dict - and variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].type == "c" - ): - min_precision = min( - min_precision, - variables_dict[name[0]][int(name[1])][int(name[2])][int(name[3])].precision, - ) - elif ( - name is variables_dict.keys() - and variables_dict[name[0]].type == "c" - and min_precision > variables_dict[name[0]].precision - ): - min_precision = variables_dict[name[0]].precision + ret = self._convert_expression_prec_no_power( + poly_field, binary_variables_name_weight, variables_dict, to_add, min_precision + ) + if isinstance(ret, bool): + return ret + to_add = ret[0] + min_precision = ret[1] if sign == "+": func += to_add From 1b8b97f6eb750579e680e2d252ec331c4a473c7f Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 10:35:18 +0200 Subject: [PATCH 40/89] add documentation files --- docs/Contributing.rst | 1 + docs/DevelopmentGuide.rst | 103 +++++++++++++++++++++++++++ docs/Quickstart.ipynb | 126 +++++++++++++++++++++++++++++++++ docs/References.rst | 6 ++ docs/Support.rst | 1 + docs/Usage.rst | 31 ++++++++ docs/_static/custom.css | 22 ++++++ docs/_static/mqt_dark.png | Bin 0 -> 61137 bytes docs/_static/mqt_light.png | Bin 0 -> 57266 bytes docs/_static/mqt_qao.png | Bin 0 -> 172047 bytes docs/_templates/page.html | 76 ++++++++++++++++++++ docs/conf.py | 140 +++++++++++++++++++++++++++++++++++++ docs/index.rst | 44 ++++++++++++ docs/refs.bib | 7 ++ 14 files changed, 557 insertions(+) create mode 100644 docs/Contributing.rst create mode 100644 docs/DevelopmentGuide.rst create mode 100644 docs/Quickstart.ipynb create mode 100644 docs/References.rst create mode 100644 docs/Support.rst create mode 100644 docs/Usage.rst create mode 100644 docs/_static/custom.css create mode 100644 docs/_static/mqt_dark.png create mode 100644 docs/_static/mqt_light.png create mode 100644 docs/_static/mqt_qao.png create mode 100644 docs/_templates/page.html create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/refs.bib diff --git a/docs/Contributing.rst b/docs/Contributing.rst new file mode 100644 index 0000000..c492978 --- /dev/null +++ b/docs/Contributing.rst @@ -0,0 +1 @@ +.. include:: ../.github/contributing.rst diff --git a/docs/DevelopmentGuide.rst b/docs/DevelopmentGuide.rst new file mode 100644 index 0000000..a8fde66 --- /dev/null +++ b/docs/DevelopmentGuide.rst @@ -0,0 +1,103 @@ +Development Guide +================= + +Ready to contribute to the project? Here is how to set up a local development environment. + +Initial Setup +############# + +1. Fork the `cda-tum/mqt-qao `_ repository on GitHub (see https://docs.github.com/en/get-started/quickstart/fork-a-repo). + +2. Clone your fork locally + + .. code-block:: console + + $ git clone git@github.com:your_name_here/mqt-qao + + +3. Change into the project directory + + .. code-block:: console + + $ cd mqt-qao + +4. Create a branch for local development + + .. code-block:: console + + $ git checkout -b name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +5. (Optional, **highly recommended**) Set up a virtual environment + + .. code-block:: console + + $ python3 -m venv venv + $ source venv/bin/activate + + .. note:: + + If you are using Windows, you can use the following command instead: + + .. code-block:: console + + $ python3 -m venv venv + $ venv\Scripts\activate.bat + + Ensure that pip, setuptools, and wheel are up to date: + + .. code-block:: console + + (venv) $ pip install --upgrade pip setuptools wheel + + +6. (Optional) Install `pre-commit `_ to automatically run a set of checks before each commit. + + .. code-block:: console + + (venv) $ pipx install pre-commit + (venv) $ pre-commit install + + If you use macOS, then pre-commit is in brew, use :code:`brew install pre-commit`. + +Building the Python module +########################## + +The recommended way of building the Python module is to perform an editable install using `pip `_. + + .. code-block:: console + + (venv) $ pip install -e . + +The :code:`--editable` flag ensures that changes in the Python code are instantly available without re-running the command. + +Running Python Tests +-------------------- + +The Python part of the code base is tested by unit tests using the `pytest `_ framework. +The corresponding test files can be found in the :code:`tests/` directory. + + .. code-block:: console + + (venv) $ pip install -e ".[test]" + (venv) $ pytest + +This installs all dependencies necessary to run the tests in an isolated environment, builds the Python package, and then runs the tests. + +Python Code Formatting and Linting +---------------------------------- + +The Python code is formatted and linted using a collection of `pre-commit hooks `_. +This collection includes: + +- `ruff `_ -- an extremely fast Python linter and formatter, written in Rust. +- `mypy `_ -- a static type checker for Python code + + +You can install the hooks manually by running :code:`pre-commit install` in the project root directory. +The hooks will then be executed automatically when committing changes. + + .. code-block:: console + + (venv) $ pre-commit run -a diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb new file mode 100644 index 0000000..a2bf307 --- /dev/null +++ b/docs/Quickstart.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ea3d6be5-b9ee-4375-adee-8fa2cb690fca", + "metadata": {}, + "source": [ + "# Quickstart" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "697e4c2b", + "metadata": {}, + "outputs": [], + "source": [ + "from mqt.bench import get_benchmark\n", + "from mqt.predictor import qcompile" + ] + }, + { + "cell_type": "markdown", + "id": "02841c4f-a865-452d-a5ca-085a64eccf00", + "metadata": {}, + "source": [ + "## Generate Uncompiled Quantum Circuit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73c0a2f9-adbd-4f85-8843-b6ab2ef53da8", + "metadata": {}, + "outputs": [], + "source": [ + "qc = get_benchmark(\"ghz\", level=\"indep\", circuit_size=5)\n", + "qc.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ebf087c-b03f-4050-b452-ecf9d698f5e7", + "metadata": {}, + "outputs": [], + "source": [ + "qc_compiled, compilation_information, quantum_device = qcompile(qc)" + ] + }, + { + "cell_type": "markdown", + "id": "dc5b2a05-c062-46d8-b75e-2bfde4795a19", + "metadata": {}, + "source": [ + "## Predicted Device" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3f643db-f833-433c-87f8-65cdc5355304", + "metadata": {}, + "outputs": [], + "source": [ + "print(quantum_device)" + ] + }, + { + "cell_type": "markdown", + "id": "7b823498-55e1-47df-9b7b-f5f462f38c50", + "metadata": {}, + "source": [ + "## Predicted and Conducted Compilation Passes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c327466-7905-45b9-980a-f96ca8cffadb", + "metadata": {}, + "outputs": [], + "source": [ + "print(compilation_information)" + ] + }, + { + "cell_type": "markdown", + "id": "53953b24-353e-465e-b4f4-d7c0f2f0f0bf", + "metadata": {}, + "source": [ + "## Compiled Circuit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", + "metadata": {}, + "outputs": [], + "source": [ + "qc_compiled.draw()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/References.rst b/docs/References.rst new file mode 100644 index 0000000..3e01e37 --- /dev/null +++ b/docs/References.rst @@ -0,0 +1,6 @@ +References +========== + +If you use *MQT Quantum Auto Optimizer* in your work, we would appreciate if you cited :cite:labelpar:`quetschlich2023mqtpredictor` (which subsumes :cite:labelpar:`volpe2024towards`). + +.. bibliography:: diff --git a/docs/Support.rst b/docs/Support.rst new file mode 100644 index 0000000..dbda9df --- /dev/null +++ b/docs/Support.rst @@ -0,0 +1 @@ +.. include:: ../.github/support.rst diff --git a/docs/Usage.rst b/docs/Usage.rst new file mode 100644 index 0000000..f36776a --- /dev/null +++ b/docs/Usage.rst @@ -0,0 +1,31 @@ +Repository Usage +================ +There are two ways how to use MQT Quantum Auto Optimizer: + +#. Via the pip package ``mqt.qao`` +#. Directly via this repository + +Usage via pip package +--------------------- + +MQT Quantum Auto Optimizer is available via `PyPI `_ + +.. code-block:: console + + (venv) $ pip install mqt.predictor + + +.. _pip_usage: + +Usage directly via this repository +---------------------------------- + +For that, the repository must be cloned and installed: + +.. code-block:: + + git clone https://github.com/cda-tum/mqt-qao.git + cd mqt-predictor + pip install . + +Afterwards, the package can be used as described :ref:`above `. diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..10d1b04 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,22 @@ +.acknowledgements { + margin-top: 1rem; + padding-bottom: 1rem; + padding-top: 1rem; + border-top: 1px solid var(--color-background-border); + font-size: var(--font-size--small); + color: var(--color-foreground-secondary); +} + +.acknowledgements-logos { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + grid-gap: 1em; + align-items: center; + margin-top: 0.5rem; +} +.acknowledgement { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/docs/_static/mqt_dark.png b/docs/_static/mqt_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..adc910ce84afc340b1cf899d40528786d6d971f7 GIT binary patch literal 61137 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 literal 0 HcmV?d00001 diff --git a/docs/_static/mqt_light.png b/docs/_static/mqt_light.png new file mode 100644 index 0000000000000000000000000000000000000000..be279e65bd931c10b154c39e76535a9312fdda78 GIT binary patch literal 57266 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 literal 0 HcmV?d00001 diff --git a/docs/_static/mqt_qao.png b/docs/_static/mqt_qao.png new file mode 100644 index 0000000000000000000000000000000000000000..674d1ea76ea57ade5b304b31457292c7abe55b01 GIT binary patch literal 172047 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 VF^PTgAp; + {% if next -%} + +

+ + + {%- endif %} {% if prev -%} + + +
+
+ {{ _("Previous") }} +
+ {% if prev.link == pathto(master_doc) %} +
{{ _("Home") }}
+ {% else %} +
{{ prev.title }}
+ {% endif %} +
+
+ {%- endif %} + +
+ The Munich Quantum Toolkit has been supported by the European Research Council + (ERC) under the European Union's Horizon 2020 research and innovation program + (grant agreement No. 101001318), the Bavarian State Ministry for Science and + Arts through the Distinguished Professorship Program, as well as the Munich + Quantum Valley, which is supported by the Bavarian state government with funds + from the Hightech Agenda Bayern Plus. +
+
+ TUM Logo +
+
+ TUM Logo +
+
+ Coat of Arms of Bavaria +
+
+ ERC Logo +
+
+ ERC Logo +
+
+ MQV Logo +
+
+
+{% endblock footer %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..db6174d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,140 @@ +"""Sphinx configuration file.""" + +from __future__ import annotations + +import warnings +from importlib import metadata +from pathlib import Path +from typing import TYPE_CHECKING + +import pybtex.plugin +from pybtex.style.formatting.unsrt import Style as UnsrtStyle +from pybtex.style.template import field, href + +ROOT = Path(__file__).parent.parent.resolve() + + +try: + version = metadata.version("mqt.qao") +except ModuleNotFoundError: + msg = ( + "Package should be installed to produce documentation! " + "Assuming a modern git archive was used for version discovery." + ) + warnings.warn(msg, stacklevel=1) + + from setuptools_scm import get_version + + version = get_version(root=str(ROOT), fallback_root=ROOT) + +# Filter git details from version +release = version.split("+")[0] +if TYPE_CHECKING: + from pybtex.database import Entry + from pybtex.richtext import HRef + +project = "MQT Quantum Auto Optimizer" +author = "Chair for Design Automation, Technical University of Munich" +language = "en" +project_copyright = "2024, Chair for Design Automation, Technical University of Munich" +# -- General configuration --------------------------------------------------- + +master_doc = "index" + +templates_path = ["_templates"] +html_css_files = ["custom.css"] + +extensions = [ + "sphinx.ext.napoleon", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.mathjax", + "sphinx.ext.intersphinx", + "sphinx.ext.autosectionlabel", + "sphinx.ext.viewcode", + "sphinx.ext.githubpages", + "sphinxcontrib.bibtex", + "sphinx_copybutton", + "hoverxref.extension", + "nbsphinx", + "sphinxext.opengraph", + "sphinx_autodoc_typehints", +] + +pygments_style = "colorful" + +add_module_names = False + +modindex_common_prefix = ["mqt.qao."] + +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "typing_extensions": ("https://typing-extensions.readthedocs.io/en/latest/", None), + "qiskit": ("https://qiskit.org/documentation/", None), + "mqt": ("https://mqt.readthedocs.io/en/latest/", None), +} + +nbsphinx_execute = "never" +highlight_language = "python3" +nbsphinx_execute_arguments = [ + "--InlineBackend.figure_formats={'svg', 'pdf'}", + "--InlineBackend.rc=figure.dpi=200", +] +nbsphinx_kernel_name = "python3" + +autosectionlabel_prefix_document = True + +hoverxref_auto_ref = True +hoverxref_domains = ["cite", "py"] +hoverxref_roles = [] +hoverxref_mathjax = True +hoverxref_role_types = { + "ref": "tooltip", + "p": "tooltip", + "labelpar": "tooltip", + "class": "tooltip", + "meth": "tooltip", + "func": "tooltip", + "attr": "tooltip", + "property": "tooltip", +} +exclude_patterns = ["_build", "build", "**.ipynb_checkpoints", "Thumbs.db", ".DS_Store", ".env"] + + +class CDAStyle(UnsrtStyle): + """Custom style for including PDF links.""" + + def format_url(self, _e: Entry) -> HRef: + """Format URL field as a link to the PDF.""" + url = field("url", raw=True) + return href()[url, "[PDF]"] + + +pybtex.plugin.register_plugin("pybtex.style.formatting", "cda_style", CDAStyle) + +bibtex_bibfiles = ["refs.bib"] +bibtex_default_style = "cda_style" + +copybutton_prompt_text = r"(?:\(venv\) )?(?:\[.*\] )?\$ " +copybutton_prompt_is_regexp = True +copybutton_line_continuation_character = "\\" + +autosummary_generate = True + + +typehints_use_rtype = False +napoleon_use_rtype = False +napoleon_google_docstring = True +napoleon_numpy_docstring = False + +# -- Options for HTML output ------------------------------------------------- +html_theme = "furo" +html_static_path = ["_static"] +html_theme_options = { + "light_logo": "mqt_dark.png", + "dark_logo": "mqt_light.png", + "source_repository": "https://github.com/cda-tum/mqt-qao/", + "source_branch": "main", + "source_directory": "docs/", + "navigation_with_keys": True, +} diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..3403595 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,44 @@ +Welcome to MQT Quantum Auto Optimizer's documentation! +========================================= + +MQT Quantum Auto Optimizer is a tool for automatic framework to assist users in utilizing quantum solvers for optimization tasks while preserving interfaces that closely resemble conventional optimization practices as part of the `Munich Quantum Toolkit `_ (*MQT*) by the `Chair for Design Automation `_ at the `Technical University of Munich `_. + +From a user's perspective, the framework is used as follows: + +.. image:: /_static/mqt_qao.png + :width: 100% + :alt: Illustration of the MQT Quantum Auto Optimizer framework + :align: center + +The framework prompts users to specify variables, optimization criteria, as well as validity constraints and, afterwards, allows them to choose the desired solver. Subsequently, it automatically transforms the problem description into a format compatible with the chosen solver and provides the resulting solution. Additionally, the framework offers instruments for analyzing solution validity and quality. + +If you are interested in the theory behind MQT Quantum Auto Optimizer, have a look at the publications in the :doc:`references list `. + + +---- + + .. toctree:: + :hidden: + + self + + .. toctree:: + :maxdepth: 1 + :caption: User Guide + :glob: + + Quickstart + Usage + DeviceSelection + Compilation + FigureOfMerit + References + + .. toctree:: + :maxdepth: 1 + :caption: Developers + :glob: + + Contributing + DevelopmentGuide + Support diff --git a/docs/refs.bib b/docs/refs.bib new file mode 100644 index 0000000..8b0f86a --- /dev/null +++ b/docs/refs.bib @@ -0,0 +1,7 @@ +@MISC{volpe2024towards, + AUTHOR = {D.Volpe and N. Quetschlich and M. Graziano and G. Turvani and R. Wille}, + TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, + YEAR = {2024}, + EPRINT = {}, + EPRINTTYPE = {}, +} \ No newline at end of file From 1da35e547ff88a7f956129f90642b1bc8b69743c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 08:35:59 +0000 Subject: [PATCH 41/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/refs.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/refs.bib b/docs/refs.bib index 8b0f86a..306c981 100644 --- a/docs/refs.bib +++ b/docs/refs.bib @@ -4,4 +4,4 @@ @MISC{volpe2024towards YEAR = {2024}, EPRINT = {}, EPRINTTYPE = {}, -} \ No newline at end of file +} From c77a921f66df26fbe85d13063b3c79567ce3bdd3 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 10:37:25 +0200 Subject: [PATCH 42/89] add documentation files --- docs/conf.py | 3 ++- docs/refs.bib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index db6174d..e1c0e42 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,8 @@ class CDAStyle(UnsrtStyle): """Custom style for including PDF links.""" - def format_url(self, _e: Entry) -> HRef: + @staticmethod + def format_url( _e: Entry) -> HRef: """Format URL field as a link to the PDF.""" url = field("url", raw=True) return href()[url, "[PDF]"] diff --git a/docs/refs.bib b/docs/refs.bib index 8b0f86a..306c981 100644 --- a/docs/refs.bib +++ b/docs/refs.bib @@ -4,4 +4,4 @@ @MISC{volpe2024towards YEAR = {2024}, EPRINT = {}, EPRINTTYPE = {}, -} \ No newline at end of file +} From cee314391cd0f377f85917da6987893038d355b6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 08:38:14 +0000 Subject: [PATCH 43/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index e1c0e42..5db9e1f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -105,7 +105,7 @@ class CDAStyle(UnsrtStyle): """Custom style for including PDF links.""" @staticmethod - def format_url( _e: Entry) -> HRef: + def format_url(_e: Entry) -> HRef: """Format URL field as a link to the PDF.""" url = field("url", raw=True) return href()[url, "[PDF]"] From fc5430c4baf20960f30093821eba1f6c12c0b562 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 10:42:45 +0200 Subject: [PATCH 44/89] add documentation files --- .readthedocs.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..70bdcc5 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,30 @@ +version: 2 + +submodules: + include: all + recursive: true + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + post_checkout: + # Skip docs build if the commit message contains "skip ci" + - (git --no-pager log --pretty="tformat:%s -- %b" -1 | grep -viq "skip ci") || exit 183 + # Skip docs build if there are no changes related to docs + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml src/mqt/ .github/contributing* .github/workflows/support*; + then + exit 183; + fi + +sphinx: + configuration: docs/conf.py + +python: + install: + - method: pip + path: . + extra_requirements: + - docs From fb5885b4ded3a942e8adf0faea70daf731dc78d1 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:01:09 +0200 Subject: [PATCH 45/89] add documentation files --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index e13bb21..5a12557 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,7 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", + "rectangle-packer<=2.0.1" ] build-backend = "setuptools.build_meta" From 0fc3365836cc8f05b77aacf3da80f4da96187969 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:09:04 +0200 Subject: [PATCH 46/89] add documentation files --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5a12557..e13bb21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,6 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", - "rectangle-packer<=2.0.1" ] build-backend = "setuptools.build_meta" From 0a95d544c2b041bd48b52da07c81678e19bae925 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:32:03 +0200 Subject: [PATCH 47/89] add documentation files --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index e13bb21..1f6441b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,8 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", + "wheel", + "rectangle-packer<=2.0.1" ] build-backend = "setuptools.build_meta" From 5be37eda76296e47192467bbb5eb256e91e10ac3 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:33:13 +0200 Subject: [PATCH 48/89] add documentation files --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f6441b..5a12557 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,6 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", - "wheel", "rectangle-packer<=2.0.1" ] build-backend = "setuptools.build_meta" From 3a280adcf1b2955b02d757f795e77799fd4931d9 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:35:50 +0200 Subject: [PATCH 49/89] add documentation files --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5a12557..e13bb21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,6 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", - "rectangle-packer<=2.0.1" ] build-backend = "setuptools.build_meta" From 6643fc03d6da4d05e9f563bff0705f83c4a6ba9b Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:43:14 +0200 Subject: [PATCH 50/89] add documentation files --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index e13bb21..31b7b12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ dependencies = [ "docplex>=2.21.207", "dwave-system>=1.21.0", "dwave-samplers>=1.2.0", + "rectangle-packer<=2.0.1" ] classifiers = [ From d39f80b29d11edd4e41811feb34f4d4d8bf4c0ed Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:49:34 +0200 Subject: [PATCH 51/89] add documentation files --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 31b7b12..612b35b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "docplex>=2.21.207", "dwave-system>=1.21.0", "dwave-samplers>=1.2.0", - "rectangle-packer<=2.0.1" + "rectangle-packer<=1.1.1" ] classifiers = [ From 3393be5b9dde161a014cc85bb1545bbbc034dd9d Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 11:52:32 +0200 Subject: [PATCH 52/89] add documentation files --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 612b35b..e13bb21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ dependencies = [ "docplex>=2.21.207", "dwave-system>=1.21.0", "dwave-samplers>=1.2.0", - "rectangle-packer<=1.1.1" ] classifiers = [ From d38808313f7df86a61c142529b45f6258df5e4f2 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 13:33:49 +0200 Subject: [PATCH 53/89] add documentation files --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index e13bb21..8b2ed5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,7 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", + "cython", ] build-backend = "setuptools.build_meta" From 4dd90da5c8cfd386c005864a8584a2897afee9c4 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 13:45:06 +0200 Subject: [PATCH 54/89] add documentation files --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8b2ed5d..939cb76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,9 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", + "wheel", "cython", + "rectangle-packer==2.0.2" ] build-backend = "setuptools.build_meta" From f79f836a7823718e9d790a5d09f0a6dc4fe47dbd Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 13:47:58 +0200 Subject: [PATCH 55/89] add documentation files --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 939cb76..de33ca7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,6 @@ requires = [ "setuptools_scm>=8.1", "wheel", "cython", - "rectangle-packer==2.0.2" ] build-backend = "setuptools.build_meta" From adbcb5b3c59893c6f7d05493818a20d12b409715 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Mon, 3 Jun 2024 14:42:00 +0200 Subject: [PATCH 56/89] Apply suggestions from code review --- .readthedocs.yaml | 2 +- docs/References.rst | 2 +- docs/index.rst | 2 +- pyproject.toml | 2 -- src/mqt/qao/solvers.py | 8 ++++---- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 70bdcc5..20ae190 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -14,7 +14,7 @@ build: - (git --no-pager log --pretty="tformat:%s -- %b" -1 | grep -viq "skip ci") || exit 183 # Skip docs build if there are no changes related to docs - | - if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml src/mqt/ .github/contributing* .github/workflows/support*; + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml src/mqt/ .github/contributing* .github/support*; then exit 183; fi diff --git a/docs/References.rst b/docs/References.rst index 3e01e37..2a446d8 100644 --- a/docs/References.rst +++ b/docs/References.rst @@ -1,6 +1,6 @@ References ========== -If you use *MQT Quantum Auto Optimizer* in your work, we would appreciate if you cited :cite:labelpar:`quetschlich2023mqtpredictor` (which subsumes :cite:labelpar:`volpe2024towards`). +If you use *MQT Quantum Auto Optimizer* in your work, we would appreciate if you cited :cite:labelpar:`volpe2024towards`. .. bibliography:: diff --git a/docs/index.rst b/docs/index.rst index 3403595..b6ee8c4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,7 +1,7 @@ Welcome to MQT Quantum Auto Optimizer's documentation! ========================================= -MQT Quantum Auto Optimizer is a tool for automatic framework to assist users in utilizing quantum solvers for optimization tasks while preserving interfaces that closely resemble conventional optimization practices as part of the `Munich Quantum Toolkit `_ (*MQT*) by the `Chair for Design Automation `_ at the `Technical University of Munich `_. +MQT Quantum Auto Optimizer is a tool for automatic framework to assist users in utilizing quantum solvers for optimization tasks while preserving interfaces that closely resemble conventional optimization practices and is developed as part of the `Munich Quantum Toolkit `_ (*MQT*) by the `Chair for Design Automation `_ at the `Technical University of Munich `_. From a user's perspective, the framework is used as follows: diff --git a/pyproject.toml b/pyproject.toml index de33ca7..e13bb21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,8 +2,6 @@ requires = [ "setuptools>=66.1", "setuptools_scm>=8.1", - "wheel", - "cython", ] build-backend = "setuptools.build_meta" diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index 1aa79f5..85d59e8 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -1068,7 +1068,7 @@ def show_cumulative( rc("text", usetex=True) plt.rc("text", usetex=True) if label: - _n, _bins, _patches = plt.hist( + plt.hist( self.energies, cumulative=True, histtype="step", @@ -1077,17 +1077,17 @@ def show_cumulative( label=r"\textit{" + label + "}", ) else: - _n, _bins, _patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) + plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) plt.title(r"\textbf{Cumulative distribution}", fontsize=20) plt.xlabel(r"\textit{Energy}", fontsize=20) plt.ylabel(r"\textit{occurrence}", fontsize=20) else: if label: - _n, _bins, _patches = plt.hist( + plt.hist( self.energies, cumulative=True, histtype="step", linewidth=2, bins=100, label=label ) else: - _n, _bins, _patches = plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) + plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) plt.title("Cumulative distribution", fontsize=20) plt.xlabel("Energy", fontsize=20) plt.ylabel("occurrence", fontsize=20) From 84b5ee7f272b61bc6a3a42fb7f31a46eb9d4931d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:42:16 +0000 Subject: [PATCH 57/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/qao/solvers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mqt/qao/solvers.py b/src/mqt/qao/solvers.py index 85d59e8..c9eddca 100644 --- a/src/mqt/qao/solvers.py +++ b/src/mqt/qao/solvers.py @@ -1083,9 +1083,7 @@ def show_cumulative( plt.ylabel(r"\textit{occurrence}", fontsize=20) else: if label: - plt.hist( - self.energies, cumulative=True, histtype="step", linewidth=2, bins=100, label=label - ) + plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100, label=label) else: plt.hist(self.energies, cumulative=True, histtype="step", linewidth=2, bins=100) plt.title("Cumulative distribution", fontsize=20) From 79c47669e2e33495c99d83b30f8fe836bbddfa86 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Mon, 3 Jun 2024 15:30:04 +0200 Subject: [PATCH 58/89] add documentation files --- docs/Quickstart.ipynb | 118 +++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 25 deletions(-) diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb index a2bf307..4e9924e 100644 --- a/docs/Quickstart.ipynb +++ b/docs/Quickstart.ipynb @@ -13,10 +13,20 @@ "execution_count": null, "id": "697e4c2b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ - "from mqt.bench import get_benchmark\n", - "from mqt.predictor import qcompile" + "from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables" ] }, { @@ -24,7 +34,7 @@ "id": "02841c4f-a865-452d-a5ca-085a64eccf00", "metadata": {}, "source": [ - "## Generate Uncompiled Quantum Circuit" + "## Declare the variables of the problem" ] }, { @@ -32,74 +42,131 @@ "execution_count": null, "id": "73c0a2f9-adbd-4f85-8843-b6ab2ef53da8", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], + "source": [ + "var = Variables()\n", + "a = var.add_binary_variable(\"a\")\n", + "b = var.add_discrete_variable(\"b\", [-1, 1, 3])\n", + "c = var.add_continuous_variable(\"c\", -2, 2, 0.25)" + ] + }, + { + "cell_type": "markdown", + "id": "dc5b2a05-c062-46d8-b75e-2bfde4795a19", + "metadata": {}, "source": [ - "qc = get_benchmark(\"ghz\", level=\"indep\", circuit_size=5)\n", - "qc.draw()" + "## Declare the objective functions" ] }, { "cell_type": "code", "execution_count": null, - "id": "6ebf087c-b03f-4050-b452-ecf9d698f5e7", + "id": "b3f643db-f833-433c-87f8-65cdc5355304", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ - "qc_compiled, compilation_information, quantum_device = qcompile(qc)" + "obj_func = ObjectiveFunction()\n", + "obj_func.add_objective_function(a + b * c + c**2)" ] }, { "cell_type": "markdown", - "id": "dc5b2a05-c062-46d8-b75e-2bfde4795a19", + "id": "7b823498-55e1-47df-9b7b-f5f462f38c50", "metadata": {}, "source": [ - "## Predicted Device" + "## Declare the constraints" ] }, { "cell_type": "code", "execution_count": null, - "id": "b3f643db-f833-433c-87f8-65cdc5355304", + "id": "0c327466-7905-45b9-980a-f96ca8cffadb", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ - "print(quantum_device)" + "cst = Constraints()\n", + "cst.add_constraint(\"b + c >= 2\", variable_precision=True)" ] }, { "cell_type": "markdown", - "id": "7b823498-55e1-47df-9b7b-f5f462f38c50", + "id": "53953b24-353e-465e-b4f4-d7c0f2f0f0bf", "metadata": {}, "source": [ - "## Predicted and Conducted Compilation Passes" + "## Declaration of the problem" ] }, { "cell_type": "code", "execution_count": null, - "id": "0c327466-7905-45b9-980a-f96ca8cffadb", + "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ - "print(compilation_information)" + "prb = Problem()\n", + "prb.create_problem(var, cst, obj_func)" ] }, { "cell_type": "markdown", - "id": "53953b24-353e-465e-b4f4-d7c0f2f0f0bf", + "id": "93392cb4", "metadata": {}, "source": [ - "## Compiled Circuit" + "## Solve with Quantum Annealing" ] }, { "cell_type": "code", "execution_count": null, - "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", + "id": "010ab172", "metadata": {}, "outputs": [], "source": [ - "qc_compiled.draw()" + "solution = Solver().solve_Dwave_quantum_annealer(prb, token=token)" ] } ], @@ -118,7 +185,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.9.7" } }, "nbformat": 4, From 16ea467b7194e78d8c995a7b5c7475f1e2b52371 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:31:25 +0000 Subject: [PATCH 59/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Quickstart.ipynb | 68 ++++--------------------------------------- 1 file changed, 6 insertions(+), 62 deletions(-) diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb index 4e9924e..f6eafdf 100644 --- a/docs/Quickstart.ipynb +++ b/docs/Quickstart.ipynb @@ -13,18 +13,7 @@ "execution_count": null, "id": "697e4c2b", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables" ] @@ -42,18 +31,7 @@ "execution_count": null, "id": "73c0a2f9-adbd-4f85-8843-b6ab2ef53da8", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "var = Variables()\n", "a = var.add_binary_variable(\"a\")\n", @@ -74,18 +52,7 @@ "execution_count": null, "id": "b3f643db-f833-433c-87f8-65cdc5355304", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "obj_func = ObjectiveFunction()\n", "obj_func.add_objective_function(a + b * c + c**2)" @@ -104,18 +71,7 @@ "execution_count": null, "id": "0c327466-7905-45b9-980a-f96ca8cffadb", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "cst = Constraints()\n", "cst.add_constraint(\"b + c >= 2\", variable_precision=True)" @@ -134,18 +90,7 @@ "execution_count": null, "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "prb = Problem()\n", "prb.create_problem(var, cst, obj_func)" @@ -185,8 +130,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" + "pygments_lexer": "ipython3" } }, "nbformat": 4, From 9771bede81651976ce83aa1e4c10c2475481ac50 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Mon, 3 Jun 2024 20:57:01 +0200 Subject: [PATCH 60/89] Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c7ae9f..33a1cc4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: # Python linting using ruff - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.5 + rev: v0.4.7 hooks: - id: ruff args: ["--fix", "--show-fixes"] From c1163925f149c583f4fcc8dfcb42a1b6b9e6be9d Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Mon, 3 Jun 2024 20:57:33 +0200 Subject: [PATCH 61/89] :alembic: try to add cython to nox build time dependencies --- noxfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/noxfile.py b/noxfile.py index 3ddb987..2581909 100644 --- a/noxfile.py +++ b/noxfile.py @@ -21,6 +21,7 @@ "setuptools>=66.1", "setuptools_scm>=8.1", "wheel>=0.40", + "cython>=3.0", ] if os.environ.get("CI", None): From bcc6b4b4120a03b45b3e18a5b58218f60b1a6feb Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 09:43:08 +0200 Subject: [PATCH 62/89] update custom.css --- docs/_static/custom.css | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 10d1b04..04260a5 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -20,3 +20,34 @@ align-items: center; justify-content: center; } + +/* override the default background color for literal strings */ +body:not([data-theme="light"]) .highlight .sa, +.highlight .sb, +.highlight .sc, +.highlight .dl, +.highlight .sd, +.highlight .s2, +.highlight .se, +.highlight .sh, +.highlight .si, +.highlight .sx, +.highlight .sr, +.highlight .s1, +.highlight .ss, +.highlight .s1, +.highlight .s { + background-color: #00000001; +} + +/* provide dark mode overrides for mystnb variables */ +body:not([data-theme="light"]) { + --mystnb-source-bg-color: #131416; + --mystnb-stdout-bg-color: #1a1c1e; + --mystnb-stderr-bg-color: #442222; + --mystnb-traceback-bg-color: #202020; +} + +body:not([data-theme="light"]) .highlight .gp { + color: #c65d09; +} From c9227a11dd8438144425b6a04940cfadfa5ac7a3 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 09:45:17 +0200 Subject: [PATCH 63/89] update index.rst --- docs/index.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index b6ee8c4..de8763b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ Welcome to MQT Quantum Auto Optimizer's documentation! -========================================= +===================================================== MQT Quantum Auto Optimizer is a tool for automatic framework to assist users in utilizing quantum solvers for optimization tasks while preserving interfaces that closely resemble conventional optimization practices and is developed as part of the `Munich Quantum Toolkit `_ (*MQT*) by the `Chair for Design Automation `_ at the `Technical University of Munich `_. @@ -29,9 +29,6 @@ If you are interested in the theory behind MQT Quantum Auto Optimizer, have a lo Quickstart Usage - DeviceSelection - Compilation - FigureOfMerit References .. toctree:: From 9091977c768dfc73d78e5912ff4bce96cf295262 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 09:51:30 +0200 Subject: [PATCH 64/89] update reference --- CITATION.bib | 3 +-- docs/refs.bib | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CITATION.bib b/CITATION.bib index 306c981..13f0a82 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -2,6 +2,5 @@ @MISC{volpe2024towards AUTHOR = {D.Volpe and N. Quetschlich and M. Graziano and G. Turvani and R. Wille}, TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, YEAR = {2024}, - EPRINT = {}, - EPRINTTYPE = {}, + BOOKTITLE = {2024 IEEE International Conference on Quantum Software (QSW)}, } diff --git a/docs/refs.bib b/docs/refs.bib index 306c981..13f0a82 100644 --- a/docs/refs.bib +++ b/docs/refs.bib @@ -2,6 +2,5 @@ @MISC{volpe2024towards AUTHOR = {D.Volpe and N. Quetschlich and M. Graziano and G. Turvani and R. Wille}, TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, YEAR = {2024}, - EPRINT = {}, - EPRINTTYPE = {}, + BOOKTITLE = {2024 IEEE International Conference on Quantum Software (QSW)}, } From be789bc172b207d7773196dd01a490c0e8a2997c Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 09:57:28 +0200 Subject: [PATCH 65/89] update usage.rst --- docs/Usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Usage.rst b/docs/Usage.rst index f36776a..89ec398 100644 --- a/docs/Usage.rst +++ b/docs/Usage.rst @@ -8,7 +8,7 @@ There are two ways how to use MQT Quantum Auto Optimizer: Usage via pip package --------------------- -MQT Quantum Auto Optimizer is available via `PyPI `_ +MQT Quantum Auto Optimizer is available via `PyPI `_ .. code-block:: console @@ -25,7 +25,7 @@ For that, the repository must be cloned and installed: .. code-block:: git clone https://github.com/cda-tum/mqt-qao.git - cd mqt-predictor + cd mqt-qao pip install . Afterwards, the package can be used as described :ref:`above `. From 17f1c60e4da7faf74c978f8a356b340c4ddc4362 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 09:58:43 +0200 Subject: [PATCH 66/89] update usage.rst --- docs/Usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Usage.rst b/docs/Usage.rst index 89ec398..c87827b 100644 --- a/docs/Usage.rst +++ b/docs/Usage.rst @@ -12,7 +12,7 @@ MQT Quantum Auto Optimizer is available via `PyPI Date: Wed, 5 Jun 2024 10:23:54 +0200 Subject: [PATCH 67/89] update documentation files --- docs/Quickstart.ipynb | 78 +++++++++++++++++++++++++++++++++++++------ tests/__init__.py | 5 --- 2 files changed, 68 insertions(+), 15 deletions(-) delete mode 100644 tests/__init__.py diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb index f6eafdf..e45a2ad 100644 --- a/docs/Quickstart.ipynb +++ b/docs/Quickstart.ipynb @@ -10,10 +10,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "697e4c2b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'mqt'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmqt\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mqao\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Constraints, ObjectiveFunction, Problem, Solver, Variables\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'mqt'" + ] + } + ], "source": [ "from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables" ] @@ -28,10 +40,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "73c0a2f9-adbd-4f85-8843-b6ab2ef53da8", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'Variables' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[3], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m var \u001b[38;5;241m=\u001b[39m \u001b[43mVariables\u001b[49m()\n\u001b[0;32m 2\u001b[0m a \u001b[38;5;241m=\u001b[39m var\u001b[38;5;241m.\u001b[39madd_binary_variable(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 3\u001b[0m b \u001b[38;5;241m=\u001b[39m var\u001b[38;5;241m.\u001b[39madd_discrete_variable(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m, [\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m3\u001b[39m])\n", + "\u001b[1;31mNameError\u001b[0m: name 'Variables' is not defined" + ] + } + ], "source": [ "var = Variables()\n", "a = var.add_binary_variable(\"a\")\n", @@ -52,7 +76,18 @@ "execution_count": null, "id": "b3f643db-f833-433c-87f8-65cdc5355304", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ "obj_func = ObjectiveFunction()\n", "obj_func.add_objective_function(a + b * c + c**2)" @@ -71,7 +106,18 @@ "execution_count": null, "id": "0c327466-7905-45b9-980a-f96ca8cffadb", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ "cst = Constraints()\n", "cst.add_constraint(\"b + c >= 2\", variable_precision=True)" @@ -90,7 +136,18 @@ "execution_count": null, "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ "prb = Problem()\n", "prb.create_problem(var, cst, obj_func)" @@ -101,7 +158,7 @@ "id": "93392cb4", "metadata": {}, "source": [ - "## Solve with Quantum Annealing" + "## Solve with Simulated Annealing" ] }, { @@ -111,7 +168,7 @@ "metadata": {}, "outputs": [], "source": [ - "solution = Solver().solve_Dwave_quantum_annealer(prb, token=token)" + "solution = Solver().solve_simulated_annealing(prb)" ] } ], @@ -130,7 +187,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.9.7" } }, "nbformat": 4, diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 3b90ab3..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""MQT QAO. - -This file is part of the MQT QAO library released under the MIT license. -See README.md or go to https://github.com/cda-tum/mqt-predictor for more information. -""" From 33d56074d92de6454ead805d9f9e457724e68ec1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:25:28 +0000 Subject: [PATCH 68/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Quickstart.ipynb | 74 +++++-------------------------------------- 1 file changed, 8 insertions(+), 66 deletions(-) diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb index e45a2ad..cf194f7 100644 --- a/docs/Quickstart.ipynb +++ b/docs/Quickstart.ipynb @@ -10,22 +10,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "697e4c2b", "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'mqt'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmqt\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mqao\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Constraints, ObjectiveFunction, Problem, Solver, Variables\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'mqt'" - ] - } - ], + "outputs": [], "source": [ "from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables" ] @@ -40,22 +28,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "73c0a2f9-adbd-4f85-8843-b6ab2ef53da8", "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'Variables' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[3], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m var \u001b[38;5;241m=\u001b[39m \u001b[43mVariables\u001b[49m()\n\u001b[0;32m 2\u001b[0m a \u001b[38;5;241m=\u001b[39m var\u001b[38;5;241m.\u001b[39madd_binary_variable(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 3\u001b[0m b \u001b[38;5;241m=\u001b[39m var\u001b[38;5;241m.\u001b[39madd_discrete_variable(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m, [\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m3\u001b[39m])\n", - "\u001b[1;31mNameError\u001b[0m: name 'Variables' is not defined" - ] - } - ], + "outputs": [], "source": [ "var = Variables()\n", "a = var.add_binary_variable(\"a\")\n", @@ -76,18 +52,7 @@ "execution_count": null, "id": "b3f643db-f833-433c-87f8-65cdc5355304", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "obj_func = ObjectiveFunction()\n", "obj_func.add_objective_function(a + b * c + c**2)" @@ -106,18 +71,7 @@ "execution_count": null, "id": "0c327466-7905-45b9-980a-f96ca8cffadb", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "cst = Constraints()\n", "cst.add_constraint(\"b + c >= 2\", variable_precision=True)" @@ -136,18 +90,7 @@ "execution_count": null, "id": "fe643f31-9d3e-4b7f-875a-af27e3dab5ed", "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName\\python.exe' requires the ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -p c:\\Users\\39333\\miniconda3\\envs\\MyEnvironmentName ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "prb = Problem()\n", "prb.create_problem(var, cst, obj_func)" @@ -187,8 +130,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" + "pygments_lexer": "ipython3" } }, "nbformat": 4, From 78065784935f298be17ef3594827098e31c42ba0 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 12:31:46 +0200 Subject: [PATCH 69/89] variables class documentation --- docs/Variable.rst | 90 +++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 91 insertions(+) create mode 100644 docs/Variable.rst diff --git a/docs/Variable.rst b/docs/Variable.rst new file mode 100644 index 0000000..4f1ed96 --- /dev/null +++ b/docs/Variable.rst @@ -0,0 +1,90 @@ +Variables Class +=============== + +It manages the optimization problems variables. + +Variables types supported +------------------------- +Three types of variables are supported: + +- Binary variables: + - unipolar, assuming 0 or 1 values + - bipolar, assuming -1 or 1 values +- Discrete variables, assuming a user-provided list of values +- Continuous variables, assuming all values in a user-provided range with a specified step + +Variables declarations +---------------------- +The class provides methods to declare variables: + +- *add_binary_variable(name: str)*, for adding binary variables + - *name*: variable name +- *add_binary_variable_array(name: str, shape: list[int])*, for adding array of binary variables (supports 1, 2, and 3 dimensional arrays of variables) + - *name*: variable name + - *shape*: list of integers representing the shape of the array +- *add_spin_variable(name: str)*, for adding bipolar binary variables + - *name*: variable name +- *add_spin_variable_array(name: str, shape: list[int])*, for adding array of bipolar binary variables (supports 1, 2, and 3 dimensional arrays of variables). + - *name*: variable name + - *shape*: list of integers representing the shape of the array +- *add_discrete_variable(name: str, values: list[float])*, for adding discrete variables. It needs the set of values. + - *name*: variable name + - *values*: list of values that the variable can assume +- *add_discrete_variable_array(name: str, values: list[float], shape: list[int])*, for adding array of discrete variables. Consider for all the same set of values (supports 1, 2, and 3 dimensional arrays of variables). + - *name*: variable name + - *values*: list of values that the variable can assume + - *shape*: list of integers representing the shape of the array +- *add_continuous_variable(name: str, min_val: float, max_val: float, precision: float, distribution: str = "uniform", encoding_mechanism: str = "")*, for adding continuous variables. It needs the min, max values and the wanted precision. + - *name*: variable name + - *values*: list of values + - *min_val*: minimum value that the variable can assume + - *max_val*: maximum value that the variable can assume + - *precision*: precision of the values that the variable can assume. If logarithmic encoding is considered the values must the wanted power of the base of the logarithm. + - *distribution*: distribution of the values in the range. It can be one among: + - *uniform* + - *geometric* + - *logarithmic* + - *encoding_mechanism*: encoding mechanism for the variable. By default logarithmic encoding is chosen if the precision is a power of two, arithmetic progression otherwise. It can be one among: + - *dictionary* + - *unitary* + - *logarithmic _base_*, with the possibility of specifying the base of the logarithm. Two is considered as default. + - *arithmetic progression* + - *bounded coefficient _bound_*, where _bound_ is the maximum coefficient that can be used in the encoding. +- *add_continuous_variable_array(name: str, min_val: float, max_val: float, precision: float, distribution: str = "uniform", encoding_mechanism: str = "", shape: list[int])*, for adding array of continuous variables. Consider for all the same min, max values and the wanted precision (supports 1, 2, and 3 dimensional arrays of variables). + - *name*: variable name + - *values*: list of values + - *min_val*: minimum value that the variable can assume + - *max_val*: maximum value that the variable can assume + - *precision*: precision of the values that the variable can assume. If logarithmic encoding is considered the values must the wanted power of the base of the logarithm. + - *distribution*: distribution of the values in the range. It can be one among: + - *uniform* + - *geometric* + - *logarithmic* + - *encoding_mechanism*: encoding mechanism for the variable. By default logarithmic encoding is chosen if the precision is a power of two, arithmetic progression otherwise. It can be one among: + - *dictionary* + - *unitary* + - *logarithmic _base_*, with the possibility of specifying the base of the logarithm. Two is considered as default. + - *arithmetic progression* + - *bounded coefficient _bound_*, where _bound_ is the maximum coefficient that can be used in the encoding. + - *shape*: list of integers representing the shape of the array + +Examples: + +.. code-block:: python + + from mqt.qao.variables import Variables + + # Variables object declaration + variables = Variables() + + # declaration of a unipolar binary variable + a0 = variables.add_binary_variable("a") + # declaration of a discrete variable, which can assume values -1, 1, 3 + b0 = variables.add_discrete_variable("b", [-1, 1, 3]) + # declaration of a continuous variable, which can assume values in the range [-2, 2] with a precision of 0.25 + c0 = variables.add_continuous_variable("c", -2, 2, 0.25) + + # declaration of a 2D array of continuous variables in the range [-1, 1] with a precision of 0.5 + m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") + m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + diff --git a/docs/index.rst b/docs/index.rst index de8763b..9eadce4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,6 +10,7 @@ From a user's perspective, the framework is used as follows: :alt: Illustration of the MQT Quantum Auto Optimizer framework :align: center +The framework is designed to be user-friendly and to provide a high-level interface for assisting assist users in utilizing quantum solvers for optimization tasks, not requiring any prior knowledge of quantum computing. The framework prompts users to specify variables, optimization criteria, as well as validity constraints and, afterwards, allows them to choose the desired solver. Subsequently, it automatically transforms the problem description into a format compatible with the chosen solver and provides the resulting solution. Additionally, the framework offers instruments for analyzing solution validity and quality. If you are interested in the theory behind MQT Quantum Auto Optimizer, have a look at the publications in the :doc:`references list `. From a3e1fb89b364267a89fbbca1f92c108a1173b122 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:32:02 +0000 Subject: [PATCH 70/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Variable.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/Variable.rst b/docs/Variable.rst index 4f1ed96..fccd7e0 100644 --- a/docs/Variable.rst +++ b/docs/Variable.rst @@ -85,6 +85,9 @@ Examples: c0 = variables.add_continuous_variable("c", -2, 2, 0.25) # declaration of a 2D array of continuous variables in the range [-1, 1] with a precision of 0.5 - m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") - m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") - + m1 = variables.add_continuous_variables_array( + "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2" + ) + m2 = variables.add_continuous_variables_array( + "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2" + ) From 75f3c651d8ec943d4f074b83e522e2d5f2f765f2 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 12:43:11 +0200 Subject: [PATCH 71/89] Documentation structure --- docs/Constraints.rst | 2 ++ docs/ObjectiveFunction.rst | 2 ++ docs/Problem.rst | 2 ++ docs/Solution.rst | 2 ++ docs/Solver.rst | 2 ++ docs/index.rst | 6 ++++++ 6 files changed, 16 insertions(+) create mode 100644 docs/Constraints.rst create mode 100644 docs/ObjectiveFunction.rst create mode 100644 docs/Problem.rst create mode 100644 docs/Solution.rst create mode 100644 docs/Solver.rst diff --git a/docs/Constraints.rst b/docs/Constraints.rst new file mode 100644 index 0000000..323f63a --- /dev/null +++ b/docs/Constraints.rst @@ -0,0 +1,2 @@ +Constraints Class +================= diff --git a/docs/ObjectiveFunction.rst b/docs/ObjectiveFunction.rst new file mode 100644 index 0000000..586749a --- /dev/null +++ b/docs/ObjectiveFunction.rst @@ -0,0 +1,2 @@ +ObjectiveFunction Class +======================= diff --git a/docs/Problem.rst b/docs/Problem.rst new file mode 100644 index 0000000..1c95778 --- /dev/null +++ b/docs/Problem.rst @@ -0,0 +1,2 @@ +Problem Class +============= diff --git a/docs/Solution.rst b/docs/Solution.rst new file mode 100644 index 0000000..f660f6e --- /dev/null +++ b/docs/Solution.rst @@ -0,0 +1,2 @@ +Solution Class +============== diff --git a/docs/Solver.rst b/docs/Solver.rst new file mode 100644 index 0000000..b107f31 --- /dev/null +++ b/docs/Solver.rst @@ -0,0 +1,2 @@ +Solver Class +============ \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 9eadce4..63c9532 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,6 +30,12 @@ If you are interested in the theory behind MQT Quantum Auto Optimizer, have a lo Quickstart Usage + Variables + Constraints + ObjectiveFunction + Problem + Solvers + Solution References .. toctree:: From 9a8692f6e21f68a5d5aefb2d253f66fbd7719030 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:44:03 +0000 Subject: [PATCH 72/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Solver.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Solver.rst b/docs/Solver.rst index b107f31..a4e2175 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -1,2 +1,2 @@ Solver Class -============ \ No newline at end of file +============ From c3bbfc463a410ed198720b163cce64019da49acf Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 15:04:03 +0200 Subject: [PATCH 73/89] Documentation structure --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 63c9532..30c6fd7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ Welcome to MQT Quantum Auto Optimizer's documentation! -===================================================== +====================================================== MQT Quantum Auto Optimizer is a tool for automatic framework to assist users in utilizing quantum solvers for optimization tasks while preserving interfaces that closely resemble conventional optimization practices and is developed as part of the `Munich Quantum Toolkit `_ (*MQT*) by the `Chair for Design Automation `_ at the `Technical University of Munich `_. From be3a7754cc767b42a08fbdb959864f38f9be8099 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 17:11:15 +0200 Subject: [PATCH 74/89] Documentation structure --- docs/Constraints.rst | 42 ++++++++++++++++++++++++++++++ docs/ObjectiveFunction.rst | 26 +++++++++++++++++++ docs/Problem.rst | 44 ++++++++++++++++++++++++++++++++ docs/Solver.rst | 52 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) diff --git a/docs/Constraints.rst b/docs/Constraints.rst index 323f63a..ed74aab 100644 --- a/docs/Constraints.rst +++ b/docs/Constraints.rst @@ -1,2 +1,44 @@ Constraints Class ================= + +It manages the constraints of the problem. It is used to store the constraints and to check if a solution satisfies them. + +Constraints types supported +--------------------------- + +Types of constraints supported: + +- *Equality*, writing the equality as a quadratic penalty function, i.e. sum = b imposed with g = (sum-b)^2 +- *Inequality*, moving to equality with the continuous auxiliary variables a to be expanded with the encoding technique of the Variables class +- *Not constraint* among binary variables, i.e. Not(a) = b imposed with g = 2ab - a - b + 1 +- *And constraint* among binary variables, i.e. a and b = c imposed with ab -2(a+b)c + 3c +- *Or constraint* among binary variables, i.e. a or b = c imposed with ab + (a+b)(1-2c) + c +- *Xor constraint* among binary variables, i.e. a xor b = c imposed with 2ab - 2(a+b)c - 4(a+b)\_aux+4_aux c +a+b+c+4+\_aux + +Constraints declarations +---------------------- + +The class provides methods to declare variables: + +- *add_constraint(expression: str, hard: bool = True, variable_precision: bool = True)*: adds a constraint to the list of constraints. + - *expression* is a string that represents the constraint + - *hard* parameter is a boolean that indicates if the constraint is hard or soft. + - *variable_precision* parameter is a boolean that indicates if the constraint is to be considered in the precision of the variables. + +Examples: + +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + + constraint = Constraints() + variables = Variables() + variables.add_binary_variable("a") + variables.add_binary_variable("b") + variables.add_binary_variable("c") + variables.add_discrete_variable("d", [-1, 1, 3]) + variables.add_continuous_variable("e", -2, 2, 0.25, "", "") + constraint.add_constraint("~a = b", True, True, False) + constraint.add_constraint("a | b = c", True, True, False) + constraint.add_constraint("d + e <= 1", True, True, False) \ No newline at end of file diff --git a/docs/ObjectiveFunction.rst b/docs/ObjectiveFunction.rst index 586749a..98e723a 100644 --- a/docs/ObjectiveFunction.rst +++ b/docs/ObjectiveFunction.rst @@ -1,2 +1,28 @@ ObjectiveFunction Class ======================= + +It manages the objective functions of the optimization problem. it permits to specify the weights of the objectives in case of multi-objective optimization and the optimization directions. Since the variables can be declared in array form, matrix expressions for the objective functions are supported. + +Objective functions declarations +-------------------------------- + +The class provides methods to declare variables: + +- *add_objective_function(objective_function: Expr, minimization: bool = True, weight: float = 1)* : add an objective function to the optimization problem. + - *objective_function* is an expression of the variables of the optimization problem. + - *minimization* parameter specifies if the objective function is to be minimized or maximized (optimization direction). + - *weight* parameter is the weight of the objective function in case of multi-objective optimization. + +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + + variables = Variables() + constraint = Constraints() + a0 = variables.add_binary_variable("a") + b0 = variables.add_discrete_variable("b", [-1, 1, 3]) + c0 = variables.add_continuous_variable("c", -2, 2, 0.25, "", "") + objective_function = ObjectiveFunction() + objective_function.add_objective_function(a0 + b0 * c0 + c0**2) \ No newline at end of file diff --git a/docs/Problem.rst b/docs/Problem.rst index 1c95778..d6f0221 100644 --- a/docs/Problem.rst +++ b/docs/Problem.rst @@ -1,2 +1,46 @@ Problem Class ============= + +It may be useful to have a class that represents a problem. It includes the variables, constraints and objective function. This class can be used for constructing the quantum-compliant cost function. + +Problem declarations +-------------------- + +The class provides a method for declaring the problem: + +- *create_problem(var: Variables, constraint: Constraints, objective_functions: ObjectiveFunction)* : This method is used to declare the problem. + - *variables* instances of the Variables class + - *constraints* instances of the Constraints class + - *objective_functions* instances of the ObjectiveFunction class. + +and a method for obtaining the HUBO or PUBO formulation of the problem as qubovert PUBO object: + +- * write_the_final_cost_function( lambda_strategy: str, lambda_value: float = 1)* : This method is used to obtain the HUBO or PUBO formulation of the problem as qubovert PUBO object. The method takes two arguments: + - *lambda_strategy* The strategy to be used for the conversion of the problem to HUBO or PUBO. The possible values are: + - 'upper_bound_only_positive' + - 'maximum_coefficient' + - 'VLM' + - 'MOC' + - 'MOMC' + - 'upper lower bound naive' + - 'upper lower bound posiform and negaform method' + - 'manual' + - *lambda_value* The value of the lambda parameter if the use want to manually select it. The default value is 1.0. + +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + + variables = Variables() + constraint = Constraints() + a0 = variables.add_binary_variable("a") + b0 = variables.add_discrete_variable("b", [-1, 1, 3]) + c0 = variables.add_continuous_variable("c", -2, 2, 0.25, "", "") + constraint.add_constraint("c >= 1", True, True, False) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(a0 + b0 * c0 + c0**2) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + pubo = problem.write_the_final_cost_function(lambda_strategy) \ No newline at end of file diff --git a/docs/Solver.rst b/docs/Solver.rst index a4e2175..bb5add4 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -1,2 +1,54 @@ Solver Class ============ + +It interface the problems with the quantum solvers. + +Supported solvers +----------------- + +The framework currently supports the following solvers:ù + +- D-Wave quantum annealer +- D-Wave simulated annealer +- qiskit Quantum Approximate Optimization Algorithm (QAOA) +- qiskit Variational Quantum Eigensolver (VQE) +- qiskit Grover Adaptive Search (GAS) + +Solver Selection and Configuration +---------------------------------- + +The class provides for exploiting the solver: + +- *solve_simulated_annealing( + problem: Problem, + auto_setting: bool = False, + beta_range: list[float] | None = None, + num_reads: int = 100, + annealing_time: int = 100, + num_sweeps_per_beta: int = 1, + beta_schedule_type: str = "geometric", + seed: int | None = None, + initial_states: SampleSet | None = None, + initial_states_generator: str = "random", + max_lambda_update: int = 5, + lambda_update_mechanism: str = "sequential penalty increase", + lambda_strategy: str = "upper lower bound posiform and negaform method", + lambda_value: float = 1.0, + save_time: bool = False, + )* : Solve the problem using the simulated annealer. The parameters are: + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *beta_range*: the range of beta values to use + - *num_reads*: the number of reads + - *annealing_time*: the annealing time + - *num_sweeps_per_beta*: the number of sweeps per beta + - *beta_schedule_type*: the beta schedule type + - *seed*: the seed + - *initial_states*: the initial states + - *initial_states_generator*: the initial states generator + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* + From e4035535735fe850716bcc20200c6064ca58a1d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:11:35 +0000 Subject: [PATCH 75/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Constraints.rst | 2 +- docs/ObjectiveFunction.rst | 2 +- docs/Problem.rst | 2 +- docs/Solver.rst | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/Constraints.rst b/docs/Constraints.rst index ed74aab..7418d5f 100644 --- a/docs/Constraints.rst +++ b/docs/Constraints.rst @@ -41,4 +41,4 @@ Examples: variables.add_continuous_variable("e", -2, 2, 0.25, "", "") constraint.add_constraint("~a = b", True, True, False) constraint.add_constraint("a | b = c", True, True, False) - constraint.add_constraint("d + e <= 1", True, True, False) \ No newline at end of file + constraint.add_constraint("d + e <= 1", True, True, False) diff --git a/docs/ObjectiveFunction.rst b/docs/ObjectiveFunction.rst index 98e723a..841f2ef 100644 --- a/docs/ObjectiveFunction.rst +++ b/docs/ObjectiveFunction.rst @@ -25,4 +25,4 @@ The class provides methods to declare variables: b0 = variables.add_discrete_variable("b", [-1, 1, 3]) c0 = variables.add_continuous_variable("c", -2, 2, 0.25, "", "") objective_function = ObjectiveFunction() - objective_function.add_objective_function(a0 + b0 * c0 + c0**2) \ No newline at end of file + objective_function.add_objective_function(a0 + b0 * c0 + c0**2) diff --git a/docs/Problem.rst b/docs/Problem.rst index d6f0221..ff567ee 100644 --- a/docs/Problem.rst +++ b/docs/Problem.rst @@ -43,4 +43,4 @@ and a method for obtaining the HUBO or PUBO formulation of the problem as qubove objective_function.add_objective_function(a0 + b0 * c0 + c0**2) problem = Problem() problem.create_problem(variables, constraint, objective_function) - pubo = problem.write_the_final_cost_function(lambda_strategy) \ No newline at end of file + pubo = problem.write_the_final_cost_function(lambda_strategy) diff --git a/docs/Solver.rst b/docs/Solver.rst index bb5add4..5c3a14e 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -51,4 +51,3 @@ The class provides for exploiting the solver: - *sequential penalty increase* - *scaled sequential penalty increase* - *binary search penalty algorithm* - From c5f069d5f55284b695a4c8d25a673c293a29260a Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 19:48:37 +0200 Subject: [PATCH 76/89] Documentation --- README.md | 2 +- docs/Constraints.rst | 3 +- docs/ObjectiveFunction.rst | 3 + docs/Problem.rst | 3 + docs/Solution.rst | 80 +++++++++++ docs/Solver.rst | 264 ++++++++++++++++++++++++++++++++++++- docs/Variable.rst | 4 +- 7 files changed, 353 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 183fa7d..894a621 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ # MQT Quantum Auto Optimizer: Automatic Framework for Solving Optimization Problems with Quantum Computers -MQT Quantum Auto Optimizer is a framework that allows one to automatically translate an optimization problem into a quantum-compliant formulation and to solve it with one of the main quantum solvers (Quantum Annelar, QAOA, VQE and GAS) +MQT Quantum Auto Optimizer is a framework that allows one to automatically translate an optimization problem into a quantum-compliant formulation and to solve it with one of the main quantum solvers (Quantum Annealar, Quantum Approximate Optimization Algorithm, Variational Quantum Eigensolver and Grover Adaptive Search) MQT Quantum Auto Optimizer is part of the [Munich Quantum Toolkit (MQT)](https://mqt.readthedocs.io/) developed by the [Chair for Design Automation](https://www.cda.cit.tum.de/) at the [Technical University of Munich](https://www.tum.de/). This framework has been developed in collaboration with the [VLSI Lab](https://www.vlsilab.polito.it/) of [Politecnico di Torino](https://www.polito.it). diff --git a/docs/Constraints.rst b/docs/Constraints.rst index ed74aab..17326ea 100644 --- a/docs/Constraints.rst +++ b/docs/Constraints.rst @@ -25,7 +25,8 @@ The class provides methods to declare variables: - *hard* parameter is a boolean that indicates if the constraint is hard or soft. - *variable_precision* parameter is a boolean that indicates if the constraint is to be considered in the precision of the variables. -Examples: +Example: +-------- .. code-block:: python diff --git a/docs/ObjectiveFunction.rst b/docs/ObjectiveFunction.rst index 98e723a..d2fd192 100644 --- a/docs/ObjectiveFunction.rst +++ b/docs/ObjectiveFunction.rst @@ -13,6 +13,9 @@ The class provides methods to declare variables: - *minimization* parameter specifies if the objective function is to be minimized or maximized (optimization direction). - *weight* parameter is the weight of the objective function in case of multi-objective optimization. +Example: +-------- + .. code-block:: python from mqt.qao.constraints import Constraints diff --git a/docs/Problem.rst b/docs/Problem.rst index d6f0221..2f1e6bb 100644 --- a/docs/Problem.rst +++ b/docs/Problem.rst @@ -27,6 +27,9 @@ and a method for obtaining the HUBO or PUBO formulation of the problem as qubove - 'manual' - *lambda_value* The value of the lambda parameter if the use want to manually select it. The default value is 1.0. +Example: +-------- + .. code-block:: python from mqt.qao.constraints import Constraints diff --git a/docs/Solution.rst b/docs/Solution.rst index f660f6e..fcd1d17 100644 --- a/docs/Solution.rst +++ b/docs/Solution.rst @@ -1,2 +1,82 @@ Solution Class ============== + +It is a class that is used to store all the information about the solution of the problem. + +Solution Attributes +------------------- + +The class has the following attributes: + +- energies: list[float], i.e. the list of energies of the solution obtained in each run +- best_energy, i.e. the lowest energy obtained in all the runs +- best_solution: dict[str, Any], i.e. the best solution obtained in all the runs in binary variables +- best_solution_original_var: dict[str, Any], i.e. the best solution obtained in all the runs in variables originally declared +- solutions_original_var: list[dict[str, Any]], i.e. the list of solutions obtained in each run in variables originally declared +- solutions: list[dict[str, Any]], i.e. the list of solutions obtained in each run in binary variables +- time: float: the time taken to solve the problem +- solver_info: dict[str, Any], i.e. the information about the solver setting to solve the problem + + +Solution Methods +---------------- + +The class has the following methods for helping users in analyzing the solution: + +- *optimal_solution_cost_functions_values()*: This method is used to get the cost functions values of the best solution obtained in all the runs +- *check_constraint_optimal_solution()*: This method is used to check if the best solution obtained in all the runs satisfies the constraints +- *check_constraint_all_solutions()*: This method is used to check if all the solutions obtained in all the runs satisfy the constraints +- *show_cumulative(save: bool = False, show: bool = True, filename: str = "", label: str = "", latex: bool = False)* : This method is used to show the cumulative plot of the energies obtained in all the runs. The parameters are: + - save: bool, i.e. whether to save the plot or not in a file + - show: bool, i.e. whether to show the plot or not + - filename: str, i.e. the name of the file where the plot will be saved + - label: str, i.e. the label of the plot + - latex: bool, i.e. whether to show the plot in latex format or not +- *valid_solutions(weak: bool = True)*: This method is used to get the rate of valid solutions obtained in all the runs. The parameters are: + - weak: bool, i.e. whether to consider in the evaluation the weak constraints +- *p_range(ref_value: float | None = None)*: This method is used to get the p-range of the best solution obtained in all the runs, which is the probability of obtaining a final energy lower than a certain value. The parameters are: + - ref_value: float | None, i.e. the reference value to calculate the p-value +- *tts(ref_value: float | None = None, target_probability: float = 0.99)*: This method is used to get the time-to-solution of the best solution obtained in all the runs, which is the time required to obtain a solution with a certain probability. The parameters are: + - ref_value: float | None, i.e. the reference value to calculate the p-range + - target_probability: float, i.e. the target probability to calculate the time-to-solution +-*wring_json_reports(filename: str = "report", weak: bool = False, ref_value: float | None = None, target_probability: float = 0.99, problem_features: bool = False)* : This method is used to write the reports in json format. The parameters are: + - filename: str, i.e. the name of the file where the report will be saved + - weak: bool, i.e. whether to consider in the evaluation the weak constraints + - ref_value: float | None, i.e. the reference value to calculate the p-range + - target_probability: float, i.e. the target probability to calculate the time-to-solution + - problem_features: bool, i.e. whether to show the problem features in the report or not + + +Examples: +--------- + +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + from mqt.qao.problem import Problem + from mqt.qao.solver import Solver + + variables = Variables() + m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") + m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + objective_function = ObjectiveFunction() + objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) + constraint = Constraints() + constraint.add_constraint(constraint_expr, variable_precision=True) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_simulated_annealing( + problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + ) + + print(solution.optimal_solution_cost_functions_values()) + print(solution.check_constraint_optimal_solution()) + print(solution.check_constraint_all_solutions()) + solution.show_cumulative() + print(solution.valid_solutions()) + print(solution.p_range()) + print(solution.tts()) + solution.wring_json_reports() diff --git a/docs/Solver.rst b/docs/Solver.rst index bb5add4..91e0d2a 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -19,7 +19,7 @@ Solver Selection and Configuration The class provides for exploiting the solver: -- *solve_simulated_annealing( +- solve_simulated_annealing( problem: Problem, auto_setting: bool = False, beta_range: list[float] | None = None, @@ -35,7 +35,7 @@ The class provides for exploiting the solver: lambda_strategy: str = "upper lower bound posiform and negaform method", lambda_value: float = 1.0, save_time: bool = False, - )* : Solve the problem using the simulated annealer. The parameters are: + ) : Solve the problem using the simulated annealer. The parameters are: - *problem*: the problem to solve - *auto_setting*: if True, the parameters are automatically set - *beta_range*: the range of beta values to use @@ -51,4 +51,264 @@ The class provides for exploiting the solver: - *sequential penalty increase* - *scaled sequential penalty increase* - *binary search penalty algorithm* +- solve_dwave_quantum_annealer( + problem: Problem, + token: str, + auto_setting: bool = False, + failover: bool = True, + config_file: str | None = None, + endpoint: str | None = None, + solver: dict[str, str] | str = "Advantage_system4.1", + annealing_time_scheduling: float | list[list[float]] = 20.0, + num_reads: int = 100, + auto_scale: bool = True, + flux_drift_compensation: bool = True, + initial_state: dict[str, int] | None = None, + programming_thermalization: float = 1000.0, + readout_thermalization: float = 0.0, + reduce_intersample_correlation: bool = True, + max_lambda_update: int = 5, + lambda_update_mechanism: str = "sequential penalty increase", + lambda_strategy: str = "upper lower bound posiform and negaform method", + lambda_value: float = 1.0, + save_time: bool = False, + save_compilation_time: bool = False, + ) : Solve the problem using the D-Wave quantum annealer. The parameters are: + - *problem*: the problem to solve + - *token*: the token to access the D-Wave API + - *auto_setting*: if True, the parameters are automatically set + - *failover*: if True, the failover is enabled + - *config_file*: the configuration file + - *endpoint*: the endpoint + - *solver*: the solver to use + - *annealing_time_scheduling*: the annealing time scheduling + - *num_reads*: the number of reads + - *auto_scale*: if True, the problem is automatically scaled + - *flux_drift_compensation*: if True, the flux drift compensation is enabled + - *initial_state*: the initial state + - *programming_thermalization*: the programming thermalization + - *readout_thermalization*: the readout thermalization + - *reduce_intersample_correlation*: if True, the intersample correlation is reduced + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* +- solve_grover_adaptive_search_qubo( + problem: Problem, + auto_setting: bool = False, + qubit_values: int = 0, + coeff_precision: float = 1.0, + threshold: int = 10, + num_runs: int = 10, + max_lambda_update: int = 5, + boundaries_estimation_method: str = "", + lambda_update_mechanism: str = "sequential penalty increase", + lambda_strategy: str = "upper lower bound posiform and negaform method", + lambda_value: float = 1.0, + save_time: bool = False, + save_compilation_time: bool = False, + ) : Solve the problem using the Grover Adaptive Search. The parameters are: + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *qubit_values*: the number of qubit values, if the user want to specify it manually + - *coeff_precision*: the coefficient precision + - *threshold*: the threshold + - *num_runs*: the number of runs + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *boundaries_estimation_method*: the boundaries estimation method for estimating the necessary number of qubit value + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* +- solve_qaoa_qubo( + problem: Problem, + auto_setting: bool = False, + num_runs: int = 10, + optimizer: Optimizer | None = None, + reps: int = 1, + initial_state: QuantumCircuit | None = None, + mixer: QuantumCircuit = None, + initial_point: np.ndarray[Any, Any] | None = None, + aggregation: float | Callable[[list[float]], float] | None = None, + callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, + max_lambda_update: int = 5, + lambda_update_mechanism: str = "sequential penalty increase", + lambda_strategy: str = "upper lower bound posiform and negaform method", + lambda_value: float = 1.0, + save_time: bool = False, + save_compilation_time: bool = False, + ) : Solve the problem using the Quantum Approximate Optimization Algorithm. The parameters are: + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *num_runs*: the number of runs + - *optimizer*: the optimizer + - *reps*: the number of repetitions + - *initial_state*: the initial state + - *mixer*: the mixer + - *initial_point*: the initial point + - *aggregation*: the aggregation function + - *callback*: the callback function + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* +- solve_vqe_qubo( + self, + problem: Problem, + auto_setting: bool = False, + num_runs: int = 10, + optimizer: Optimizer | None = None, + ansatz: QuantumCircuit | None = None, + initial_point: np.ndarray[Any, Any] | None = None, + aggregation: float | Callable[[list[float]], float] | None = None, + callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, + max_lambda_update: int = 5, + lambda_update_mechanism: str = "sequential penalty increase", + lambda_strategy: str = "upper lower bound posiform and negaform method", + lambda_value: float = 1.0, + save_time: bool = False, + save_compilation_time: bool = False, + ) : Solve the problem using the Variational Quantum Eigensolver. The parameters are: + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *num_runs*: the number of runs + - *optimizer*: the optimizer + - *ansatz*: the ansatz + - *initial_point*: the initial point + - *aggregation*: the aggregation function + - *callback*: the callback function + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* + +For each of them, the outcome is a Solution object. + + +Examples: +--------- + +Simulated Annealing +~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + from mqt.qao.problem import Problem + from mqt.qao.solver import Solver + + variables = Variables() + m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") + m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + objective_function = ObjectiveFunction() + objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) + constraint = Constraints() + constraint.add_constraint(constraint_expr, variable_precision=True) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_simulated_annealing( + problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + ) + +Quantum Annealing +~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + from mqt.qao.problem import Problem + from mqt.qao.solver import Solver + + variables = Variables() + m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") + m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + objective_function = ObjectiveFunction() + objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) + constraint = Constraints() + constraint.add_constraint(constraint_expr, variable_precision=True) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_dwave_quantum_annealer( + token, problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + ) + + +Grover Adaptive Search +~~~~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + from mqt.qao.problem import Problem + from mqt.qao.solver import Solver + + variables = Variables() + constraint = Constraints() + a0 = variables.add_binary_variable("a") + b0 = variables.add_binary_variable("b") + c0 = variables.add_binary_variable("c") + cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(cost_function) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_grover_adaptive_search_qubo(problem, qubit_values=6, num_runs=10) + + + +Quantum Approximate Optimization Algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + from mqt.qao.constraints import Constraints + from mqt.qao.variables import Variables + from mqt.qao.objectivefunction import ObjectiveFunction + from mqt.qao.problem import Problem + from mqt.qao.solver import Solver + + variables = Variables() + constraint = Constraints() + a0 = variables.add_binary_variable("a") + b0 = variables.add_binary_variable("b") + c0 = variables.add_binary_variable("c") + cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(cost_function) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_qaoa_qubo( + problem, + num_runs=10, + ) + + +Variational Quantum Eigensolver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + variables = Variables() + constraint = Constraints() + a0 = variables.add_binary_variable("a") + b0 = variables.add_binary_variable("b") + c0 = variables.add_binary_variable("c") + cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(cost_function) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_vqe_qubo( + problem, + num_runs=10, + ) diff --git a/docs/Variable.rst b/docs/Variable.rst index fccd7e0..4c401d4 100644 --- a/docs/Variable.rst +++ b/docs/Variable.rst @@ -68,8 +68,8 @@ The class provides methods to declare variables: - *bounded coefficient _bound_*, where _bound_ is the maximum coefficient that can be used in the encoding. - *shape*: list of integers representing the shape of the array -Examples: - +Example: +-------- .. code-block:: python from mqt.qao.variables import Variables From 8e07b0cc35903432cc760d48c1fbd1bd2253f97a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:51:08 +0000 Subject: [PATCH 77/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Solution.rst | 13 ++++++++++--- docs/Solver.rst | 32 ++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/Solution.rst b/docs/Solution.rst index fcd1d17..43f1286 100644 --- a/docs/Solution.rst +++ b/docs/Solution.rst @@ -59,8 +59,12 @@ Examples: from mqt.qao.solver import Solver variables = Variables() - m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") - m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + m1 = variables.add_continuous_variables_array( + "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2" + ) + m2 = variables.add_continuous_variables_array( + "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2" + ) objective_function = ObjectiveFunction() objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) constraint = Constraints() @@ -69,7 +73,10 @@ Examples: problem.create_problem(variables, constraint, objective_function) solver = Solver() solution = solver.solve_simulated_annealing( - problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + problem, + max_lambda_update=max_lambda_update, + lambda_update_mechanism=lambda_update, + lambda_strategy=lambda_strategy, ) print(solution.optimal_solution_cost_functions_values()) diff --git a/docs/Solver.rst b/docs/Solver.rst index 91e0d2a..f3ab436 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -202,8 +202,12 @@ Simulated Annealing from mqt.qao.solver import Solver variables = Variables() - m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") - m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + m1 = variables.add_continuous_variables_array( + "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2" + ) + m2 = variables.add_continuous_variables_array( + "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2" + ) objective_function = ObjectiveFunction() objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) constraint = Constraints() @@ -212,7 +216,10 @@ Simulated Annealing problem.create_problem(variables, constraint, objective_function) solver = Solver() solution = solver.solve_simulated_annealing( - problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + problem, + max_lambda_update=max_lambda_update, + lambda_update_mechanism=lambda_update, + lambda_strategy=lambda_strategy, ) Quantum Annealing @@ -226,8 +233,12 @@ Quantum Annealing from mqt.qao.solver import Solver variables = Variables() - m1 = variables.add_continuous_variables_array("M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2") - m2 = variables.add_continuous_variables_array("M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2") + m1 = variables.add_continuous_variables_array( + "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2" + ) + m2 = variables.add_continuous_variables_array( + "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2" + ) objective_function = ObjectiveFunction() objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0)) constraint = Constraints() @@ -236,7 +247,11 @@ Quantum Annealing problem.create_problem(variables, constraint, objective_function) solver = Solver() solution = solver.solve_dwave_quantum_annealer( - token, problem, max_lambda_update=max_lambda_update, lambda_update_mechanism=lambda_update, lambda_strategy=lambda_strategy + token, + problem, + max_lambda_update=max_lambda_update, + lambda_update_mechanism=lambda_update, + lambda_strategy=lambda_strategy, ) @@ -261,7 +276,9 @@ Grover Adaptive Search problem = Problem() problem.create_problem(variables, constraint, objective_function) solver = Solver() - solution = solver.solve_grover_adaptive_search_qubo(problem, qubit_values=6, num_runs=10) + solution = solver.solve_grover_adaptive_search_qubo( + problem, qubit_values=6, num_runs=10 + ) @@ -311,4 +328,3 @@ Variational Quantum Eigensolver problem, num_runs=10, ) - From 8e0aa20ee082ecf59efa476911125b74204d3fdb Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 19:52:36 +0200 Subject: [PATCH 78/89] Documentation --- docs/Solution.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Solution.rst b/docs/Solution.rst index 43f1286..f38295e 100644 --- a/docs/Solution.rst +++ b/docs/Solution.rst @@ -47,6 +47,7 @@ The class has the following methods for helping users in analyzing the solution: - problem_features: bool, i.e. whether to show the problem features in the report or not + Examples: --------- From b7c7f257b1711303b5cbcdd3eda37461fd680626 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Wed, 5 Jun 2024 20:32:28 +0200 Subject: [PATCH 79/89] Use cases --- scripts/Knapsack/Data/f10_l-d_kp_20_879 | 21 + scripts/Knapsack/Data/f1_l-d_kp_10_269 | 11 + scripts/Knapsack/Data/f2_l-d_kp_20_878 | 21 + scripts/Knapsack/Data/f3_l-d_kp_4_20 | 5 + scripts/Knapsack/Data/f4_l-d_kp_4_11 | 5 + scripts/Knapsack/Data/f5_l-d_kp_15_375 | 16 + scripts/Knapsack/Data/f6_l-d_kp_10_60 | 11 + scripts/Knapsack/Data/f7_l-d_kp_7_50 | 8 + scripts/Knapsack/Data/f8_l-d_kp_23_10000 | 24 + scripts/Knapsack/Data/f9_l-d_kp_5_80 | 6 + scripts/Knapsack/Data/knapPI_1_1000_1000_1 | 1002 +++++++++ scripts/Knapsack/Data/knapPI_1_100_1000_1 | 102 + scripts/Knapsack/Data/knapPI_1_2000_1000_1 | 2002 +++++++++++++++++ scripts/Knapsack/Data/knapPI_1_200_1000_1 | 202 ++ scripts/Knapsack/Data/knapPI_1_500_1000_1 | 502 +++++ scripts/Knapsack/Data/knapPI_2_1000_1000_1 | 1002 +++++++++ scripts/Knapsack/Data/knapPI_2_100_1000_1 | 102 + scripts/Knapsack/Data/knapPI_2_2000_1000_1 | 2002 +++++++++++++++++ scripts/Knapsack/Data/knapPI_2_200_1000_1 | 202 ++ scripts/Knapsack/Data/knapPI_2_500_1000_1 | 502 +++++ scripts/Knapsack/Data/knapPI_3_1000_1000_1 | 1002 +++++++++ scripts/Knapsack/Data/knapPI_3_100_1000_1 | 102 + scripts/Knapsack/Data/knapPI_3_2000_1000_1 | 2002 +++++++++++++++++ scripts/Knapsack/Data/knapPI_3_200_1000_1 | 202 ++ scripts/Knapsack/Data/knapPI_3_500_1000_1 | 502 +++++ scripts/Knapsack/Knapsack.py | 109 + scripts/linear_regression/LinearRegression.py | 159 ++ scripts/linear_regression/iris_csv.csv | 101 + 28 files changed, 11927 insertions(+) create mode 100644 scripts/Knapsack/Data/f10_l-d_kp_20_879 create mode 100644 scripts/Knapsack/Data/f1_l-d_kp_10_269 create mode 100644 scripts/Knapsack/Data/f2_l-d_kp_20_878 create mode 100644 scripts/Knapsack/Data/f3_l-d_kp_4_20 create mode 100644 scripts/Knapsack/Data/f4_l-d_kp_4_11 create mode 100644 scripts/Knapsack/Data/f5_l-d_kp_15_375 create mode 100644 scripts/Knapsack/Data/f6_l-d_kp_10_60 create mode 100644 scripts/Knapsack/Data/f7_l-d_kp_7_50 create mode 100644 scripts/Knapsack/Data/f8_l-d_kp_23_10000 create mode 100644 scripts/Knapsack/Data/f9_l-d_kp_5_80 create mode 100644 scripts/Knapsack/Data/knapPI_1_1000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_1_100_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_1_2000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_1_200_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_1_500_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_2_1000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_2_100_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_2_2000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_2_200_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_2_500_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_3_1000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_3_100_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_3_2000_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_3_200_1000_1 create mode 100644 scripts/Knapsack/Data/knapPI_3_500_1000_1 create mode 100644 scripts/Knapsack/Knapsack.py create mode 100644 scripts/linear_regression/LinearRegression.py create mode 100644 scripts/linear_regression/iris_csv.csv diff --git a/scripts/Knapsack/Data/f10_l-d_kp_20_879 b/scripts/Knapsack/Data/f10_l-d_kp_20_879 new file mode 100644 index 0000000..e2cc105 --- /dev/null +++ b/scripts/Knapsack/Data/f10_l-d_kp_20_879 @@ -0,0 +1,21 @@ +20 879 +91 84 +72 83 +90 43 +46 4 +55 44 +8 6 +35 82 +75 92 +61 25 +15 83 +77 56 +40 18 +63 58 +75 14 +29 48 +75 70 +17 96 +78 32 +40 68 +44 92 diff --git a/scripts/Knapsack/Data/f1_l-d_kp_10_269 b/scripts/Knapsack/Data/f1_l-d_kp_10_269 new file mode 100644 index 0000000..4adaa2c --- /dev/null +++ b/scripts/Knapsack/Data/f1_l-d_kp_10_269 @@ -0,0 +1,11 @@ +10 269 +55 95 +10 4 +47 60 +5 32 +4 23 +50 72 +8 80 +61 62 +85 65 +87 46 diff --git a/scripts/Knapsack/Data/f2_l-d_kp_20_878 b/scripts/Knapsack/Data/f2_l-d_kp_20_878 new file mode 100644 index 0000000..2a9148e --- /dev/null +++ b/scripts/Knapsack/Data/f2_l-d_kp_20_878 @@ -0,0 +1,21 @@ +20 878 +44 92 +46 4 +90 43 +72 83 +91 84 +40 68 +75 92 +35 82 +8 6 +54 44 +78 32 +40 18 +77 56 +15 83 +61 25 +17 96 +75 70 +29 48 +75 14 +63 58 diff --git a/scripts/Knapsack/Data/f3_l-d_kp_4_20 b/scripts/Knapsack/Data/f3_l-d_kp_4_20 new file mode 100644 index 0000000..7388b39 --- /dev/null +++ b/scripts/Knapsack/Data/f3_l-d_kp_4_20 @@ -0,0 +1,5 @@ +4 20 +9 6 +11 5 +13 9 +15 7 diff --git a/scripts/Knapsack/Data/f4_l-d_kp_4_11 b/scripts/Knapsack/Data/f4_l-d_kp_4_11 new file mode 100644 index 0000000..1630d23 --- /dev/null +++ b/scripts/Knapsack/Data/f4_l-d_kp_4_11 @@ -0,0 +1,5 @@ +4 11 +6 2 +10 4 +12 6 +13 7 diff --git a/scripts/Knapsack/Data/f5_l-d_kp_15_375 b/scripts/Knapsack/Data/f5_l-d_kp_15_375 new file mode 100644 index 0000000..ff150c3 --- /dev/null +++ b/scripts/Knapsack/Data/f5_l-d_kp_15_375 @@ -0,0 +1,16 @@ +15 375 +0.125126 56.358531 +19.330424 80.874050 +58.500931 47.987304 +35.029145 89.596240 +82.284005 74.660482 +17.410810 85.894345 +71.050142 51.353496 +30.399487 1.498459 +9.140294 36.445204 +14.731285 16.589862 +98.852504 44.569231 +11.908322 0.466933 +0.891140 37.788018 +53.166295 57.118442 +60.176397 60.716575 diff --git a/scripts/Knapsack/Data/f6_l-d_kp_10_60 b/scripts/Knapsack/Data/f6_l-d_kp_10_60 new file mode 100644 index 0000000..587b40d --- /dev/null +++ b/scripts/Knapsack/Data/f6_l-d_kp_10_60 @@ -0,0 +1,11 @@ +10 60 +20 30 +18 25 +17 20 +15 18 +15 17 +10 11 +5 5 +3 2 +1 1 +1 1 diff --git a/scripts/Knapsack/Data/f7_l-d_kp_7_50 b/scripts/Knapsack/Data/f7_l-d_kp_7_50 new file mode 100644 index 0000000..04963f9 --- /dev/null +++ b/scripts/Knapsack/Data/f7_l-d_kp_7_50 @@ -0,0 +1,8 @@ +7 50 +70 31 +20 10 +39 20 +37 19 +7 4 +5 3 +10 6 diff --git a/scripts/Knapsack/Data/f8_l-d_kp_23_10000 b/scripts/Knapsack/Data/f8_l-d_kp_23_10000 new file mode 100644 index 0000000..1dd6547 --- /dev/null +++ b/scripts/Knapsack/Data/f8_l-d_kp_23_10000 @@ -0,0 +1,24 @@ +23 10000 +981 983 +980 982 +979 981 +978 980 +977 979 +976 978 +487 488 +974 976 +970 972 +485 486 +485 486 +970 972 +970 972 +484 485 +484 485 +976 969 +974 966 +482 483 +962 964 +961 963 +959 961 +958 958 +857 959 diff --git a/scripts/Knapsack/Data/f9_l-d_kp_5_80 b/scripts/Knapsack/Data/f9_l-d_kp_5_80 new file mode 100644 index 0000000..9c6bafd --- /dev/null +++ b/scripts/Knapsack/Data/f9_l-d_kp_5_80 @@ -0,0 +1,6 @@ +5 80 +33 15 +24 20 +36 17 +37 8 +12 31 diff --git a/scripts/Knapsack/Data/knapPI_1_1000_1000_1 b/scripts/Knapsack/Data/knapPI_1_1000_1000_1 new file mode 100644 index 0000000..bae8935 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_1_1000_1000_1 @@ -0,0 +1,1002 @@ +1000 5002 +94 485 +506 326 +416 248 +992 421 +649 322 +237 795 +457 43 +815 845 +446 955 +422 252 +791 9 +359 901 +667 122 +598 94 +7 738 +544 574 +334 715 +766 882 +994 367 +893 984 +633 299 +131 433 +428 682 +700 72 +617 874 +874 138 +720 856 +419 145 +794 995 +196 529 +997 199 +116 277 +908 97 +539 719 +707 242 +569 107 +537 122 +931 70 +726 98 +487 600 +772 645 +513 267 +81 972 +943 895 +58 213 +303 748 +764 487 +536 923 +724 29 +789 674 +479 540 +142 554 +339 467 +641 46 +196 710 +494 553 +66 191 +824 724 +208 730 +711 988 +800 90 +314 340 +289 549 +401 196 +466 865 +689 678 +833 570 +225 936 +244 722 +849 651 +113 123 +379 431 +361 508 +65 585 +486 853 +686 642 +286 992 +889 725 +24 286 +491 812 +891 859 +90 663 +181 88 +214 179 +17 187 +472 619 +418 261 +419 846 +356 192 +682 261 +306 514 +201 886 +385 530 +952 849 +500 294 +194 799 +737 391 +324 330 +992 298 +224 790 +260 275 +97 826 +210 72 +649 866 +919 951 +63 748 +958 685 +804 956 +518 564 +428 183 +537 400 +346 721 +153 207 +971 323 +662 611 +197 116 +91 109 +529 795 +126 343 +747 862 +469 685 +770 10 +934 881 +723 984 +895 403 +568 360 +172 449 +958 541 +383 272 +308 877 +970 359 +583 707 +48 308 +930 770 +569 30 +3 208 +20 311 +609 100 +887 939 +825 422 +930 785 +904 370 +241 989 +379 969 +376 143 +962 972 +889 28 +443 61 +216 638 +338 348 +160 347 +406 66 +159 391 +31 638 +204 295 +420 826 +153 196 +425 449 +331 855 +565 143 +838 487 +9 140 +918 564 +533 615 +232 135 +957 564 +591 360 +576 793 +746 163 +377 859 +858 760 +86 711 +434 662 +558 159 +279 660 +840 268 +735 948 +574 315 +126 676 +912 341 +739 689 +821 894 +625 706 +917 490 +201 478 +993 671 +149 932 +52 899 +759 237 +267 187 +256 472 +783 772 +117 98 +516 906 +180 911 +25 635 +380 225 +712 823 +266 164 +216 343 +448 732 +541 502 +664 740 +954 576 +726 612 +772 902 +531 454 +943 411 +750 973 +327 703 +917 850 +5 77 +113 220 +913 802 +791 403 +998 181 +859 10 +345 525 +431 919 +675 668 +833 527 +438 462 +523 291 +916 605 +420 457 +115 405 +660 417 +261 279 +772 685 +388 596 +764 307 +843 224 +206 322 +407 840 +639 975 +852 401 +542 91 +60 327 +757 330 +82 182 +637 603 +93 793 +614 615 +136 733 +187 864 +102 16 +972 863 +163 987 +501 306 +477 34 +492 840 +121 700 +80 706 +138 787 +660 105 +229 834 +827 798 +448 310 +230 609 +832 690 +489 561 +586 579 +291 60 +665 388 +660 309 +702 407 +153 200 +606 313 +123 970 +253 33 +709 273 +832 277 +108 997 +888 40 +481 227 +283 860 +858 940 +284 608 +711 990 +850 590 +239 806 +943 52 +195 801 +95 764 +410 710 +664 386 +900 593 +112 50 +963 494 +754 156 +458 936 +19 965 +225 86 +569 723 +97 184 +194 868 +754 340 +602 412 +61 487 +695 209 +347 346 +719 860 +100 307 +97 95 +843 821 +745 941 +286 821 +492 587 +116 201 +531 665 +424 527 +253 812 +426 424 +413 459 +980 343 +291 836 +833 506 +486 179 +9 916 +575 430 +922 596 +145 808 +897 269 +404 512 +742 811 +728 685 +269 567 +103 776 +745 855 +35 718 +779 853 +71 97 +80 146 +842 746 +128 15 +941 965 +227 512 +30 480 +342 958 +605 665 +531 191 +364 964 +359 515 +867 606 +820 822 +313 536 +207 693 +911 19 +308 335 +430 101 +685 922 +641 294 +113 910 +141 410 +690 250 +700 546 +559 729 +481 609 +503 720 +766 976 +7 759 +882 798 +859 74 +182 648 +425 299 +542 785 +683 846 +853 390 +938 897 +89 416 +624 837 +181 247 +878 293 +933 144 +580 938 +252 467 +207 480 +658 955 +20 665 +954 26 +347 564 +759 449 +446 26 +14 521 +657 301 +710 321 +980 613 +188 388 +636 879 +203 990 +432 188 +129 963 +630 820 +509 300 +237 822 +373 255 +838 277 +395 153 +692 400 +103 227 +218 518 +384 447 +931 315 +396 813 +389 324 +640 502 +287 299 +297 780 +977 376 +512 516 +219 212 +555 329 +398 810 +289 486 +798 485 +598 416 +49 952 +572 894 +697 358 +770 21 +725 647 +542 44 +214 683 +887 361 +45 814 +94 231 +282 8 +82 165 +319 496 +626 699 +146 852 +541 459 +874 535 +725 314 +777 944 +554 306 +208 459 +787 637 +976 447 +912 408 +444 107 +3 962 +301 565 +164 407 +437 857 +652 317 +764 98 +41 818 +737 600 +176 288 +136 902 +128 567 +394 190 +235 749 +42 908 +824 276 +684 748 +979 592 +568 393 +367 363 +52 163 +642 983 +335 179 +126 16 +130 478 +583 259 +129 868 +752 295 +167 596 +856 71 +640 622 +770 864 +431 644 +195 5 +448 365 +701 429 +952 64 +880 854 +168 770 +79 88 +961 157 +472 368 +217 421 +709 719 +147 271 +296 975 +909 816 +764 962 +251 535 +878 438 +753 696 +570 881 +253 318 +666 45 +931 52 +433 496 +810 313 +678 138 +123 334 +212 988 +66 508 +206 770 +750 751 +64 780 +466 441 +337 207 +510 516 +796 674 +175 408 +437 920 +938 573 +848 634 +561 878 +718 990 +948 826 +649 696 +569 800 +663 411 +582 422 +843 707 +202 334 +702 986 +579 494 +725 150 +803 562 +340 380 +156 832 +832 979 +602 376 +234 511 +688 414 +184 160 +978 982 +413 238 +633 490 +585 899 +606 251 +963 526 +350 897 +242 39 +539 657 +739 452 +267 538 +165 831 +177 460 +720 185 +802 934 +644 440 +82 490 +798 168 +197 71 +173 977 +81 458 +235 204 +112 803 +103 139 +268 399 +879 420 +643 991 +106 578 +122 972 +444 177 +262 398 +691 348 +997 496 +446 276 +171 825 +549 614 +281 121 +211 730 +112 341 +408 284 +730 698 +363 17 +89 546 +605 672 +938 974 +168 866 +705 377 +47 559 +400 340 +215 527 +114 779 +51 761 +881 483 +549 92 +679 390 +328 583 +250 661 +203 391 +481 336 +752 661 +707 125 +82 89 +63 275 +660 359 +21 178 +287 780 +219 42 +500 5 +820 380 +95 772 +44 816 +748 9 +678 484 +276 545 +478 589 +663 157 +594 901 +757 777 +947 74 +448 247 +570 55 +313 479 +981 785 +795 958 +552 680 +389 393 +280 944 +864 596 +636 619 +512 611 +892 852 +184 283 +947 299 +614 766 +625 312 +149 826 +377 726 +474 733 +18 805 +662 679 +416 403 +1 964 +530 337 +752 541 +22 478 +981 369 +777 946 +957 821 +275 833 +584 837 +582 490 +121 37 +951 594 +668 129 +118 258 +319 246 +896 362 +521 755 +948 504 +248 71 +474 177 +351 176 +54 803 +155 237 +660 677 +871 33 +486 115 +294 597 +425 769 +245 536 +382 956 +371 341 +708 184 +544 234 +794 569 +387 216 +738 537 +520 84 +281 810 +502 657 +91 33 +503 159 +924 520 +16 668 +33 287 +344 229 +349 374 +606 474 +896 672 +595 915 +441 511 +102 123 +52 569 +654 199 +710 396 +434 715 +245 59 +36 610 +661 917 +413 927 +13 270 +370 117 +400 516 +195 215 +984 216 +476 237 +164 615 +405 499 +674 477 +196 760 +608 285 +907 56 +532 966 +51 622 +716 221 +327 194 +880 91 +710 347 +267 252 +400 473 +376 516 +609 385 +320 357 +196 958 +538 665 +935 792 +404 64 +100 420 +126 671 +855 968 +94 877 +731 177 +253 523 +8 139 +393 152 +543 732 +348 246 +318 565 +489 740 +22 902 +998 17 +49 973 +381 298 +10 611 +429 32 +221 11 +150 337 +717 136 +530 889 +332 522 +942 805 +565 28 +216 931 +61 757 +170 609 +872 544 +644 905 +208 595 +680 246 +697 113 +639 175 +679 156 +961 244 +361 883 +802 265 +359 883 +839 462 +718 485 +280 272 +252 204 +280 984 +102 409 +615 398 +296 909 +481 370 +956 882 +230 214 +259 766 +922 35 +706 421 +272 271 +156 370 +552 848 +485 50 +536 976 +70 270 +902 796 +452 963 +35 379 +947 991 +378 551 +57 897 +352 307 +669 421 +702 74 +141 388 +458 559 +463 980 +756 615 +887 681 +332 231 +528 207 +656 818 +254 331 +787 979 +495 445 +370 348 +10 724 +200 401 +327 646 +17 668 +374 242 +755 302 +980 861 +376 830 +8 77 +32 441 +460 589 +804 990 +23 189 +869 868 +943 996 +715 363 +628 237 +73 420 +199 565 +38 214 +209 333 +327 726 +912 175 +799 58 +372 625 +976 66 +120 169 +667 475 +188 204 +28 90 +704 496 +649 1 +746 474 +697 449 +712 252 +289 332 +625 287 +953 189 +462 889 +302 63 +79 378 +41 206 +823 897 +908 230 +665 382 +36 575 +732 60 +809 529 +66 477 +291 290 +591 89 +583 961 +252 461 +479 702 +530 532 +224 680 +788 53 +309 642 +366 1000 +352 891 +402 822 +545 152 +113 324 +967 633 +454 267 +723 381 +14 272 +20 506 +308 419 +644 461 +713 526 +482 978 +336 468 +289 729 +496 795 +326 581 +530 383 +167 226 +522 421 +830 386 +91 273 +116 484 +747 676 +395 107 +958 229 +756 902 +262 962 +703 105 +511 84 +481 991 +449 701 +888 689 +599 655 +306 600 +492 538 +803 499 +445 881 +316 981 +889 473 +785 383 +765 679 +491 573 +589 589 +124 480 +741 145 +898 624 +725 923 +682 915 +131 232 +398 974 +906 735 +753 678 +312 640 +790 644 +301 212 +945 123 +447 253 +197 943 +27 18 +573 916 +589 327 +934 640 +209 615 +529 470 +899 655 +15 288 +592 401 +92 840 +575 633 +814 707 +354 424 +127 682 +374 194 +566 855 +594 190 +973 728 +645 178 +603 275 +712 88 +32 367 +298 544 +561 738 +906 963 +626 460 +143 266 +504 727 +836 33 +361 442 +431 628 +554 384 +24 244 +416 482 +735 765 +243 446 +454 247 +932 913 +494 560 +648 528 +357 594 +596 935 +788 462 +536 621 +759 660 +200 564 +566 302 +741 936 +217 592 +219 724 +832 118 +819 299 +487 251 +473 129 +241 96 +64 167 +516 169 +857 381 +218 976 +490 767 +504 837 +707 407 +342 203 +475 387 +175 735 +786 706 +171 335 +232 40 +888 821 +866 131 +976 159 +253 978 +619 53 +642 849 +460 478 +218 19 +218 230 +667 453 +949 336 +89 931 +488 588 +568 449 +526 566 +0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 1 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_1_100_1000_1 b/scripts/Knapsack/Data/knapPI_1_100_1000_1 new file mode 100644 index 0000000..109fc20 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_1_100_1000_1 @@ -0,0 +1,102 @@ +100 995 +94 485 +506 326 +416 248 +992 421 +649 322 +237 795 +457 43 +815 845 +446 955 +422 252 +791 9 +359 901 +667 122 +598 94 +7 738 +544 574 +334 715 +766 882 +994 367 +893 984 +633 299 +131 433 +428 682 +700 72 +617 874 +874 138 +720 856 +419 145 +794 995 +196 529 +997 199 +116 277 +908 97 +539 719 +707 242 +569 107 +537 122 +931 70 +726 98 +487 600 +772 645 +513 267 +81 972 +943 895 +58 213 +303 748 +764 487 +536 923 +724 29 +789 674 +479 540 +142 554 +339 467 +641 46 +196 710 +494 553 +66 191 +824 724 +208 730 +711 988 +800 90 +314 340 +289 549 +401 196 +466 865 +689 678 +833 570 +225 936 +244 722 +849 651 +113 123 +379 431 +361 508 +65 585 +486 853 +686 642 +286 992 +889 725 +24 286 +491 812 +891 859 +90 663 +181 88 +214 179 +17 187 +472 619 +418 261 +419 846 +356 192 +682 261 +306 514 +201 886 +385 530 +952 849 +500 294 +194 799 +737 391 +324 330 +992 298 +224 790 +0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_1_2000_1000_1 b/scripts/Knapsack/Data/knapPI_1_2000_1000_1 new file mode 100644 index 0000000..6c17313 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_1_2000_1000_1 @@ -0,0 +1,2002 @@ +2000 10011 +94 485 +506 326 +416 248 +992 421 +649 322 +237 795 +457 43 +815 845 +446 955 +422 252 +791 9 +359 901 +667 122 +598 94 +7 738 +544 574 +334 715 +766 882 +994 367 +893 984 +633 299 +131 433 +428 682 +700 72 +617 874 +874 138 +720 856 +419 145 +794 995 +196 529 +997 199 +116 277 +908 97 +539 719 +707 242 +569 107 +537 122 +931 70 +726 98 +487 600 +772 645 +513 267 +81 972 +943 895 +58 213 +303 748 +764 487 +536 923 +724 29 +789 674 +479 540 +142 554 +339 467 +641 46 +196 710 +494 553 +66 191 +824 724 +208 730 +711 988 +800 90 +314 340 +289 549 +401 196 +466 865 +689 678 +833 570 +225 936 +244 722 +849 651 +113 123 +379 431 +361 508 +65 585 +486 853 +686 642 +286 992 +889 725 +24 286 +491 812 +891 859 +90 663 +181 88 +214 179 +17 187 +472 619 +418 261 +419 846 +356 192 +682 261 +306 514 +201 886 +385 530 +952 849 +500 294 +194 799 +737 391 +324 330 +992 298 +224 790 +260 275 +97 826 +210 72 +649 866 +919 951 +63 748 +958 685 +804 956 +518 564 +428 183 +537 400 +346 721 +153 207 +971 323 +662 611 +197 116 +91 109 +529 795 +126 343 +747 862 +469 685 +770 10 +934 881 +723 984 +895 403 +568 360 +172 449 +958 541 +383 272 +308 877 +970 359 +583 707 +48 308 +930 770 +569 30 +3 208 +20 311 +609 100 +887 939 +825 422 +930 785 +904 370 +241 989 +379 969 +376 143 +962 972 +889 28 +443 61 +216 638 +338 348 +160 347 +406 66 +159 391 +31 638 +204 295 +420 826 +153 196 +425 449 +331 855 +565 143 +838 487 +9 140 +918 564 +533 615 +232 135 +957 564 +591 360 +576 793 +746 163 +377 859 +858 760 +86 711 +434 662 +558 159 +279 660 +840 268 +735 948 +574 315 +126 676 +912 341 +739 689 +821 894 +625 706 +917 490 +201 478 +993 671 +149 932 +52 899 +759 237 +267 187 +256 472 +783 772 +117 98 +516 906 +180 911 +25 635 +380 225 +712 823 +266 164 +216 343 +448 732 +541 502 +664 740 +954 576 +726 612 +772 902 +531 454 +943 411 +750 973 +327 703 +917 850 +5 77 +113 220 +913 802 +791 403 +998 181 +859 10 +345 525 +431 919 +675 668 +833 527 +438 462 +523 291 +916 605 +420 457 +115 405 +660 417 +261 279 +772 685 +388 596 +764 307 +843 224 +206 322 +407 840 +639 975 +852 401 +542 91 +60 327 +757 330 +82 182 +637 603 +93 793 +614 615 +136 733 +187 864 +102 16 +972 863 +163 987 +501 306 +477 34 +492 840 +121 700 +80 706 +138 787 +660 105 +229 834 +827 798 +448 310 +230 609 +832 690 +489 561 +586 579 +291 60 +665 388 +660 309 +702 407 +153 200 +606 313 +123 970 +253 33 +709 273 +832 277 +108 997 +888 40 +481 227 +283 860 +858 940 +284 608 +711 990 +850 590 +239 806 +943 52 +195 801 +95 764 +410 710 +664 386 +900 593 +112 50 +963 494 +754 156 +458 936 +19 965 +225 86 +569 723 +97 184 +194 868 +754 340 +602 412 +61 487 +695 209 +347 346 +719 860 +100 307 +97 95 +843 821 +745 941 +286 821 +492 587 +116 201 +531 665 +424 527 +253 812 +426 424 +413 459 +980 343 +291 836 +833 506 +486 179 +9 916 +575 430 +922 596 +145 808 +897 269 +404 512 +742 811 +728 685 +269 567 +103 776 +745 855 +35 718 +779 853 +71 97 +80 146 +842 746 +128 15 +941 965 +227 512 +30 480 +342 958 +605 665 +531 191 +364 964 +359 515 +867 606 +820 822 +313 536 +207 693 +911 19 +308 335 +430 101 +685 922 +641 294 +113 910 +141 410 +690 250 +700 546 +559 729 +481 609 +503 720 +766 976 +7 759 +882 798 +859 74 +182 648 +425 299 +542 785 +683 846 +853 390 +938 897 +89 416 +624 837 +181 247 +878 293 +933 144 +580 938 +252 467 +207 480 +658 955 +20 665 +954 26 +347 564 +759 449 +446 26 +14 521 +657 301 +710 321 +980 613 +188 388 +636 879 +203 990 +432 188 +129 963 +630 820 +509 300 +237 822 +373 255 +838 277 +395 153 +692 400 +103 227 +218 518 +384 447 +931 315 +396 813 +389 324 +640 502 +287 299 +297 780 +977 376 +512 516 +219 212 +555 329 +398 810 +289 486 +798 485 +598 416 +49 952 +572 894 +697 358 +770 21 +725 647 +542 44 +214 683 +887 361 +45 814 +94 231 +282 8 +82 165 +319 496 +626 699 +146 852 +541 459 +874 535 +725 314 +777 944 +554 306 +208 459 +787 637 +976 447 +912 408 +444 107 +3 962 +301 565 +164 407 +437 857 +652 317 +764 98 +41 818 +737 600 +176 288 +136 902 +128 567 +394 190 +235 749 +42 908 +824 276 +684 748 +979 592 +568 393 +367 363 +52 163 +642 983 +335 179 +126 16 +130 478 +583 259 +129 868 +752 295 +167 596 +856 71 +640 622 +770 864 +431 644 +195 5 +448 365 +701 429 +952 64 +880 854 +168 770 +79 88 +961 157 +472 368 +217 421 +709 719 +147 271 +296 975 +909 816 +764 962 +251 535 +878 438 +753 696 +570 881 +253 318 +666 45 +931 52 +433 496 +810 313 +678 138 +123 334 +212 988 +66 508 +206 770 +750 751 +64 780 +466 441 +337 207 +510 516 +796 674 +175 408 +437 920 +938 573 +848 634 +561 878 +718 990 +948 826 +649 696 +569 800 +663 411 +582 422 +843 707 +202 334 +702 986 +579 494 +725 150 +803 562 +340 380 +156 832 +832 979 +602 376 +234 511 +688 414 +184 160 +978 982 +413 238 +633 490 +585 899 +606 251 +963 526 +350 897 +242 39 +539 657 +739 452 +267 538 +165 831 +177 460 +720 185 +802 934 +644 440 +82 490 +798 168 +197 71 +173 977 +81 458 +235 204 +112 803 +103 139 +268 399 +879 420 +643 991 +106 578 +122 972 +444 177 +262 398 +691 348 +997 496 +446 276 +171 825 +549 614 +281 121 +211 730 +112 341 +408 284 +730 698 +363 17 +89 546 +605 672 +938 974 +168 866 +705 377 +47 559 +400 340 +215 527 +114 779 +51 761 +881 483 +549 92 +679 390 +328 583 +250 661 +203 391 +481 336 +752 661 +707 125 +82 89 +63 275 +660 359 +21 178 +287 780 +219 42 +500 5 +820 380 +95 772 +44 816 +748 9 +678 484 +276 545 +478 589 +663 157 +594 901 +757 777 +947 74 +448 247 +570 55 +313 479 +981 785 +795 958 +552 680 +389 393 +280 944 +864 596 +636 619 +512 611 +892 852 +184 283 +947 299 +614 766 +625 312 +149 826 +377 726 +474 733 +18 805 +662 679 +416 403 +1 964 +530 337 +752 541 +22 478 +981 369 +777 946 +957 821 +275 833 +584 837 +582 490 +121 37 +951 594 +668 129 +118 258 +319 246 +896 362 +521 755 +948 504 +248 71 +474 177 +351 176 +54 803 +155 237 +660 677 +871 33 +486 115 +294 597 +425 769 +245 536 +382 956 +371 341 +708 184 +544 234 +794 569 +387 216 +738 537 +520 84 +281 810 +502 657 +91 33 +503 159 +924 520 +16 668 +33 287 +344 229 +349 374 +606 474 +896 672 +595 915 +441 511 +102 123 +52 569 +654 199 +710 396 +434 715 +245 59 +36 610 +661 917 +413 927 +13 270 +370 117 +400 516 +195 215 +984 216 +476 237 +164 615 +405 499 +674 477 +196 760 +608 285 +907 56 +532 966 +51 622 +716 221 +327 194 +880 91 +710 347 +267 252 +400 473 +376 516 +609 385 +320 357 +196 958 +538 665 +935 792 +404 64 +100 420 +126 671 +855 968 +94 877 +731 177 +253 523 +8 139 +393 152 +543 732 +348 246 +318 565 +489 740 +22 902 +998 17 +49 973 +381 298 +10 611 +429 32 +221 11 +150 337 +717 136 +530 889 +332 522 +942 805 +565 28 +216 931 +61 757 +170 609 +872 544 +644 905 +208 595 +680 246 +697 113 +639 175 +679 156 +961 244 +361 883 +802 265 +359 883 +839 462 +718 485 +280 272 +252 204 +280 984 +102 409 +615 398 +296 909 +481 370 +956 882 +230 214 +259 766 +922 35 +706 421 +272 271 +156 370 +552 848 +485 50 +536 976 +70 270 +902 796 +452 963 +35 379 +947 991 +378 551 +57 897 +352 307 +669 421 +702 74 +141 388 +458 559 +463 980 +756 615 +887 681 +332 231 +528 207 +656 818 +254 331 +787 979 +495 445 +370 348 +10 724 +200 401 +327 646 +17 668 +374 242 +755 302 +980 861 +376 830 +8 77 +32 441 +460 589 +804 990 +23 189 +869 868 +943 996 +715 363 +628 237 +73 420 +199 565 +38 214 +209 333 +327 726 +912 175 +799 58 +372 625 +976 66 +120 169 +667 475 +188 204 +28 90 +704 496 +649 1 +746 474 +697 449 +712 252 +289 332 +625 287 +953 189 +462 889 +302 63 +79 378 +41 206 +823 897 +908 230 +665 382 +36 575 +732 60 +809 529 +66 477 +291 290 +591 89 +583 961 +252 461 +479 702 +530 532 +224 680 +788 53 +309 642 +366 1000 +352 891 +402 822 +545 152 +113 324 +967 633 +454 267 +723 381 +14 272 +20 506 +308 419 +644 461 +713 526 +482 978 +336 468 +289 729 +496 795 +326 581 +530 383 +167 226 +522 421 +830 386 +91 273 +116 484 +747 676 +395 107 +958 229 +756 902 +262 962 +703 105 +511 84 +481 991 +449 701 +888 689 +599 655 +306 600 +492 538 +803 499 +445 881 +316 981 +889 473 +785 383 +765 679 +491 573 +589 589 +124 480 +741 145 +898 624 +725 923 +682 915 +131 232 +398 974 +906 735 +753 678 +312 640 +790 644 +301 212 +945 123 +447 253 +197 943 +27 18 +573 916 +589 327 +934 640 +209 615 +529 470 +899 655 +15 288 +592 401 +92 840 +575 633 +814 707 +354 424 +127 682 +374 194 +566 855 +594 190 +973 728 +645 178 +603 275 +712 88 +32 367 +298 544 +561 738 +906 963 +626 460 +143 266 +504 727 +836 33 +361 442 +431 628 +554 384 +24 244 +416 482 +735 765 +243 446 +454 247 +932 913 +494 560 +648 528 +357 594 +596 935 +788 462 +536 621 +759 660 +200 564 +566 302 +741 936 +217 592 +219 724 +832 118 +819 299 +487 251 +473 129 +241 96 +64 167 +516 169 +857 381 +218 976 +490 767 +504 837 +707 407 +342 203 +475 387 +175 735 +786 706 +171 335 +232 40 +888 821 +866 131 +976 159 +253 978 +619 53 +642 849 +460 478 +218 19 +218 230 +667 453 +949 336 +89 931 +488 588 +568 449 +526 566 +860 272 +4 883 +772 731 +734 80 +259 213 +270 177 +6 872 +424 626 +204 940 +313 150 +159 379 +205 833 +25 517 +951 724 +721 973 +635 581 +293 839 +712 272 +410 412 +465 839 +366 492 +74 553 +23 718 +416 738 +764 839 +49 390 +817 588 +507 523 +152 630 +256 770 +562 746 +495 49 +414 369 +78 537 +912 115 +59 215 +259 971 +258 602 +841 551 +137 40 +590 494 +383 252 +869 158 +939 72 +282 177 +880 667 +479 483 +454 815 +730 19 +556 745 +195 339 +409 614 +580 302 +99 319 +913 670 +798 513 +318 566 +790 27 +344 322 +80 645 +468 210 +922 841 +179 925 +347 521 +231 975 +597 269 +607 929 +903 478 +310 970 +223 684 +10 231 +845 673 +905 348 +58 232 +93 727 +759 597 +912 397 +906 539 +43 907 +76 892 +552 699 +670 408 +671 361 +353 789 +837 529 +12 190 +889 880 +912 236 +377 715 +56 718 +585 439 +852 814 +715 902 +421 658 +330 410 +51 412 +840 90 +697 678 +848 951 +826 37 +198 593 +341 737 +274 211 +740 134 +339 847 +875 490 +400 95 +603 435 +474 737 +126 860 +973 310 +973 548 +581 984 +788 660 +629 86 +799 635 +475 941 +959 56 +80 372 +917 650 +91 964 +783 735 +773 682 +712 151 +655 283 +953 773 +279 643 +701 898 +706 817 +147 269 +355 731 +100 507 +498 841 +261 207 +591 752 +630 318 +374 126 +960 153 +917 101 +406 560 +759 743 +618 816 +981 980 +641 1 +131 82 +920 886 +534 377 +453 465 +397 753 +51 842 +301 547 +197 580 +910 754 +211 37 +851 548 +42 896 +919 656 +30 537 +674 78 +979 540 +764 597 +937 314 +656 845 +590 361 +337 930 +997 654 +643 841 +652 810 +632 98 +827 814 +659 898 +56 237 +97 236 +304 397 +771 468 +680 160 +344 168 +561 189 +632 123 +666 783 +235 991 +71 775 +327 565 +824 906 +1 604 +948 233 +851 693 +780 209 +603 279 +380 231 +84 675 +684 370 +757 814 +605 276 +304 238 +358 710 +294 931 +742 879 +37 492 +4 81 +707 347 +131 417 +660 582 +89 801 +455 195 +303 403 +680 247 +970 356 +934 627 +951 858 +404 803 +446 236 +349 572 +93 485 +672 586 +158 748 +772 235 +891 859 +532 788 +621 345 +347 861 +227 342 +555 779 +16 595 +303 963 +941 260 +833 366 +190 835 +622 733 +345 834 +893 442 +192 773 +430 880 +160 873 +767 793 +170 173 +810 402 +318 60 +690 628 +224 19 +52 146 +411 685 +203 138 +785 593 +219 202 +61 500 +919 89 +191 433 +711 63 +294 514 +937 865 +253 393 +103 269 +316 111 +625 614 +639 272 +641 973 +139 609 +45 236 +316 496 +218 24 +293 871 +747 227 +879 420 +633 850 +10 127 +356 170 +665 224 +536 722 +823 189 +603 597 +392 286 +258 22 +771 957 +820 536 +139 221 +566 281 +229 238 +325 531 +804 449 +786 735 +983 670 +847 646 +388 272 +632 605 +253 394 +405 508 +137 537 +283 955 +678 477 +659 969 +706 692 +786 963 +313 829 +143 638 +713 206 +244 185 +489 187 +844 129 +896 300 +602 114 +210 305 +930 199 +692 916 +457 839 +241 899 +950 452 +229 185 +212 561 +222 848 +32 191 +747 830 +869 860 +245 873 +575 649 +818 591 +204 974 +584 974 +822 452 +198 397 +942 350 +942 597 +899 13 +375 392 +327 343 +479 756 +66 387 +950 924 +464 188 +286 68 +573 552 +294 166 +137 435 +557 14 +423 797 +427 254 +95 300 +715 431 +403 367 +453 197 +735 233 +1 149 +145 62 +782 38 +848 69 +456 425 +490 810 +679 878 +461 503 +844 308 +70 798 +599 437 +888 798 +395 36 +733 583 +795 412 +368 195 +94 878 +114 388 +46 438 +795 532 +583 3 +321 268 +714 417 +332 277 +257 229 +906 445 +301 380 +277 974 +651 248 +218 433 +109 1000 +558 874 +388 939 +121 760 +372 473 +228 811 +208 766 +326 306 +572 556 +50 521 +753 364 +77 460 +266 136 +227 458 +502 784 +337 648 +31 783 +629 960 +215 137 +353 591 +274 875 +343 440 +758 263 +838 40 +478 835 +595 943 +255 749 +331 263 +362 597 +84 5 +16 999 +459 161 +220 35 +16 891 +865 459 +719 996 +292 592 +175 54 +461 985 +301 401 +759 298 +715 459 +207 77 +129 611 +681 159 +261 467 +893 737 +399 895 +377 49 +189 382 +360 285 +14 388 +728 972 +314 265 +225 729 +534 810 +914 973 +94 818 +549 295 +674 532 +434 58 +211 736 +986 187 +863 896 +802 998 +279 997 +31 476 +810 259 +968 475 +187 494 +791 130 +190 151 +410 639 +592 855 +886 480 +875 478 +763 386 +352 672 +58 361 +815 894 +562 460 +571 148 +322 660 +465 628 +418 329 +198 975 +554 1 +656 507 +108 750 +453 109 +909 915 +576 700 +646 75 +114 896 +313 229 +692 85 +759 144 +643 536 +462 919 +860 516 +904 473 +959 25 +663 25 +209 611 +564 44 +233 722 +478 980 +716 563 +616 672 +107 914 +979 541 +466 882 +971 142 +76 259 +886 35 +498 543 +150 689 +442 721 +136 142 +36 530 +37 503 +344 450 +550 248 +355 599 +980 919 +473 636 +957 181 +324 873 +859 154 +570 427 +294 604 +260 313 +674 363 +339 594 +259 813 +382 829 +660 49 +430 791 +760 554 +682 499 +664 226 +358 345 +114 432 +142 758 +19 64 +753 843 +163 637 +121 941 +94 965 +398 448 +587 857 +98 968 +142 351 +303 758 +968 351 +533 980 +982 662 +568 357 +519 914 +277 548 +622 723 +517 23 +720 170 +635 351 +55 113 +263 783 +285 766 +189 527 +628 206 +7 644 +290 258 +655 861 +387 728 +641 69 +742 128 +741 392 +793 145 +802 51 +897 112 +262 253 +193 340 +882 932 +131 817 +482 965 +573 480 +443 724 +203 839 +965 500 +75 746 +807 811 +805 373 +513 605 +472 252 +797 172 +690 394 +295 177 +784 98 +532 377 +155 486 +110 855 +884 290 +173 130 +78 355 +714 842 +633 233 +477 101 +119 686 +718 736 +15 930 +472 700 +328 69 +793 607 +199 879 +999 916 +177 960 +525 408 +948 679 +498 138 +495 185 +890 782 +906 49 +334 453 +385 630 +399 429 +338 853 +520 545 +829 651 +481 765 +99 159 +680 1000 +87 179 +802 717 +890 885 +839 32 +339 838 +883 186 +67 470 +544 185 +357 921 +457 376 +444 986 +642 934 +152 171 +59 645 +616 46 +59 681 +987 43 +353 234 +530 103 +958 496 +613 389 +838 931 +85 579 +86 132 +569 908 +479 772 +683 677 +400 343 +370 703 +882 139 +146 344 +116 387 +760 909 +407 539 +447 304 +388 655 +41 378 +658 92 +119 862 +28 411 +457 362 +198 397 +17 290 +432 152 +321 611 +427 173 +205 137 +344 946 +563 365 +304 475 +47 982 +694 920 +91 802 +961 66 +644 778 +109 744 +959 464 +969 313 +42 341 +108 685 +648 331 +49 85 +228 676 +929 91 +527 534 +967 166 +316 51 +582 966 +840 841 +575 625 +503 114 +911 16 +305 113 +989 826 +836 506 +369 738 +587 564 +232 455 +452 735 +900 264 +952 548 +81 738 +995 853 +562 575 +739 569 +705 365 +5 620 +557 264 +490 193 +294 21 +361 373 +900 84 +47 250 +205 288 +145 132 +846 151 +658 419 +849 521 +680 974 +148 655 +96 648 +210 737 +690 298 +19 187 +831 981 +679 965 +726 954 +528 166 +15 248 +564 636 +847 560 +721 563 +9 24 +700 896 +446 803 +858 16 +699 274 +271 714 +977 449 +533 229 +154 280 +756 423 +871 868 +912 124 +727 970 +968 231 +569 935 +163 808 +618 23 +685 210 +650 88 +807 151 +393 770 +276 555 +304 613 +911 866 +233 223 +42 303 +400 305 +162 306 +51 900 +734 964 +933 397 +366 898 +16 59 +177 628 +360 225 +742 537 +725 612 +868 633 +489 314 +501 478 +632 981 +365 904 +196 819 +496 108 +744 179 +145 152 +501 598 +880 349 +248 80 +683 762 +500 314 +389 513 +620 205 +91 584 +721 652 +859 894 +665 198 +416 143 +481 671 +320 302 +865 611 +126 631 +757 526 +963 526 +781 403 +240 231 +330 830 +518 283 +824 864 +935 755 +51 159 +309 220 +18 447 +863 800 +1 833 +749 805 +658 791 +577 412 +579 857 +509 408 +154 895 +923 360 +397 827 +687 971 +959 961 +617 519 +637 335 +623 238 +174 883 +775 222 +608 886 +306 708 +1000 475 +957 876 +641 123 +472 127 +726 384 +305 745 +714 284 +643 429 +708 685 +631 512 +489 503 +829 599 +746 983 +732 462 +732 992 +669 270 +422 491 +54 282 +900 831 +682 167 +666 115 +957 661 +109 564 +454 934 +964 608 +933 513 +140 53 +195 659 +24 646 +657 164 +231 763 +169 825 +128 949 +537 355 +264 811 +46 164 +4 851 +900 289 +802 392 +68 224 +450 460 +126 903 +58 347 +398 638 +486 101 +451 587 +335 797 +162 881 +106 210 +745 243 +969 969 +432 298 +159 253 +634 593 +565 453 +16 657 +610 72 +503 222 +511 319 +752 61 +55 694 +469 384 +829 801 +692 136 +177 536 +211 958 +499 647 +115 526 +984 28 +818 904 +233 509 +424 884 +976 565 +371 601 +406 323 +334 522 +784 192 +676 103 +168 451 +427 867 +432 602 +531 783 +337 311 +677 994 +537 172 +1000 51 +379 389 +103 237 +785 721 +943 597 +412 492 +572 331 +828 380 +771 259 +939 726 +594 55 +19 501 +500 459 +376 790 +689 4 +776 634 +474 117 +575 601 +953 808 +143 544 +510 542 +221 590 +615 827 +599 817 +567 617 +545 32 +727 879 +558 692 +307 685 +564 88 +331 911 +568 546 +881 580 +649 997 +746 937 +393 988 +237 351 +517 661 +521 630 +213 360 +820 908 +199 203 +813 479 +14 251 +803 162 +448 905 +207 167 +86 862 +123 369 +220 181 +158 765 +944 251 +424 909 +311 645 +399 568 +59 847 +253 538 +233 540 +312 99 +790 423 +849 246 +202 165 +552 544 +653 52 +788 131 +893 372 +113 471 +498 625 +442 684 +929 378 +86 534 +12 73 +318 540 +258 671 +524 127 +579 412 +424 972 +468 823 +364 663 +81 784 +399 588 +896 496 +151 170 +626 153 +367 199 +837 152 +640 258 +124 283 +572 289 +408 608 +358 463 +895 180 +884 329 +523 221 +438 294 +278 125 +25 625 +729 427 +996 796 +956 151 +188 867 +519 122 +35 370 +311 840 +195 115 +829 875 +784 912 +904 85 +99 969 +443 714 +0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 diff --git a/scripts/Knapsack/Data/knapPI_1_200_1000_1 b/scripts/Knapsack/Data/knapPI_1_200_1000_1 new file mode 100644 index 0000000..ba4efe4 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_1_200_1000_1 @@ -0,0 +1,202 @@ +200 1008 +94 485 +506 326 +416 248 +992 421 +649 322 +237 795 +457 43 +815 845 +446 955 +422 252 +791 9 +359 901 +667 122 +598 94 +7 738 +544 574 +334 715 +766 882 +994 367 +893 984 +633 299 +131 433 +428 682 +700 72 +617 874 +874 138 +720 856 +419 145 +794 995 +196 529 +997 199 +116 277 +908 97 +539 719 +707 242 +569 107 +537 122 +931 70 +726 98 +487 600 +772 645 +513 267 +81 972 +943 895 +58 213 +303 748 +764 487 +536 923 +724 29 +789 674 +479 540 +142 554 +339 467 +641 46 +196 710 +494 553 +66 191 +824 724 +208 730 +711 988 +800 90 +314 340 +289 549 +401 196 +466 865 +689 678 +833 570 +225 936 +244 722 +849 651 +113 123 +379 431 +361 508 +65 585 +486 853 +686 642 +286 992 +889 725 +24 286 +491 812 +891 859 +90 663 +181 88 +214 179 +17 187 +472 619 +418 261 +419 846 +356 192 +682 261 +306 514 +201 886 +385 530 +952 849 +500 294 +194 799 +737 391 +324 330 +992 298 +224 790 +260 275 +97 826 +210 72 +649 866 +919 951 +63 748 +958 685 +804 956 +518 564 +428 183 +537 400 +346 721 +153 207 +971 323 +662 611 +197 116 +91 109 +529 795 +126 343 +747 862 +469 685 +770 10 +934 881 +723 984 +895 403 +568 360 +172 449 +958 541 +383 272 +308 877 +970 359 +583 707 +48 308 +930 770 +569 30 +3 208 +20 311 +609 100 +887 939 +825 422 +930 785 +904 370 +241 989 +379 969 +376 143 +962 972 +889 28 +443 61 +216 638 +338 348 +160 347 +406 66 +159 391 +31 638 +204 295 +420 826 +153 196 +425 449 +331 855 +565 143 +838 487 +9 140 +918 564 +533 615 +232 135 +957 564 +591 360 +576 793 +746 163 +377 859 +858 760 +86 711 +434 662 +558 159 +279 660 +840 268 +735 948 +574 315 +126 676 +912 341 +739 689 +821 894 +625 706 +917 490 +201 478 +993 671 +149 932 +52 899 +759 237 +267 187 +256 472 +783 772 +117 98 +516 906 +180 911 +25 635 +380 225 +712 823 +266 164 +216 343 +0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_1_500_1000_1 b/scripts/Knapsack/Data/knapPI_1_500_1000_1 new file mode 100644 index 0000000..19f4aba --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_1_500_1000_1 @@ -0,0 +1,502 @@ +500 2543 +94 485 +506 326 +416 248 +992 421 +649 322 +237 795 +457 43 +815 845 +446 955 +422 252 +791 9 +359 901 +667 122 +598 94 +7 738 +544 574 +334 715 +766 882 +994 367 +893 984 +633 299 +131 433 +428 682 +700 72 +617 874 +874 138 +720 856 +419 145 +794 995 +196 529 +997 199 +116 277 +908 97 +539 719 +707 242 +569 107 +537 122 +931 70 +726 98 +487 600 +772 645 +513 267 +81 972 +943 895 +58 213 +303 748 +764 487 +536 923 +724 29 +789 674 +479 540 +142 554 +339 467 +641 46 +196 710 +494 553 +66 191 +824 724 +208 730 +711 988 +800 90 +314 340 +289 549 +401 196 +466 865 +689 678 +833 570 +225 936 +244 722 +849 651 +113 123 +379 431 +361 508 +65 585 +486 853 +686 642 +286 992 +889 725 +24 286 +491 812 +891 859 +90 663 +181 88 +214 179 +17 187 +472 619 +418 261 +419 846 +356 192 +682 261 +306 514 +201 886 +385 530 +952 849 +500 294 +194 799 +737 391 +324 330 +992 298 +224 790 +260 275 +97 826 +210 72 +649 866 +919 951 +63 748 +958 685 +804 956 +518 564 +428 183 +537 400 +346 721 +153 207 +971 323 +662 611 +197 116 +91 109 +529 795 +126 343 +747 862 +469 685 +770 10 +934 881 +723 984 +895 403 +568 360 +172 449 +958 541 +383 272 +308 877 +970 359 +583 707 +48 308 +930 770 +569 30 +3 208 +20 311 +609 100 +887 939 +825 422 +930 785 +904 370 +241 989 +379 969 +376 143 +962 972 +889 28 +443 61 +216 638 +338 348 +160 347 +406 66 +159 391 +31 638 +204 295 +420 826 +153 196 +425 449 +331 855 +565 143 +838 487 +9 140 +918 564 +533 615 +232 135 +957 564 +591 360 +576 793 +746 163 +377 859 +858 760 +86 711 +434 662 +558 159 +279 660 +840 268 +735 948 +574 315 +126 676 +912 341 +739 689 +821 894 +625 706 +917 490 +201 478 +993 671 +149 932 +52 899 +759 237 +267 187 +256 472 +783 772 +117 98 +516 906 +180 911 +25 635 +380 225 +712 823 +266 164 +216 343 +448 732 +541 502 +664 740 +954 576 +726 612 +772 902 +531 454 +943 411 +750 973 +327 703 +917 850 +5 77 +113 220 +913 802 +791 403 +998 181 +859 10 +345 525 +431 919 +675 668 +833 527 +438 462 +523 291 +916 605 +420 457 +115 405 +660 417 +261 279 +772 685 +388 596 +764 307 +843 224 +206 322 +407 840 +639 975 +852 401 +542 91 +60 327 +757 330 +82 182 +637 603 +93 793 +614 615 +136 733 +187 864 +102 16 +972 863 +163 987 +501 306 +477 34 +492 840 +121 700 +80 706 +138 787 +660 105 +229 834 +827 798 +448 310 +230 609 +832 690 +489 561 +586 579 +291 60 +665 388 +660 309 +702 407 +153 200 +606 313 +123 970 +253 33 +709 273 +832 277 +108 997 +888 40 +481 227 +283 860 +858 940 +284 608 +711 990 +850 590 +239 806 +943 52 +195 801 +95 764 +410 710 +664 386 +900 593 +112 50 +963 494 +754 156 +458 936 +19 965 +225 86 +569 723 +97 184 +194 868 +754 340 +602 412 +61 487 +695 209 +347 346 +719 860 +100 307 +97 95 +843 821 +745 941 +286 821 +492 587 +116 201 +531 665 +424 527 +253 812 +426 424 +413 459 +980 343 +291 836 +833 506 +486 179 +9 916 +575 430 +922 596 +145 808 +897 269 +404 512 +742 811 +728 685 +269 567 +103 776 +745 855 +35 718 +779 853 +71 97 +80 146 +842 746 +128 15 +941 965 +227 512 +30 480 +342 958 +605 665 +531 191 +364 964 +359 515 +867 606 +820 822 +313 536 +207 693 +911 19 +308 335 +430 101 +685 922 +641 294 +113 910 +141 410 +690 250 +700 546 +559 729 +481 609 +503 720 +766 976 +7 759 +882 798 +859 74 +182 648 +425 299 +542 785 +683 846 +853 390 +938 897 +89 416 +624 837 +181 247 +878 293 +933 144 +580 938 +252 467 +207 480 +658 955 +20 665 +954 26 +347 564 +759 449 +446 26 +14 521 +657 301 +710 321 +980 613 +188 388 +636 879 +203 990 +432 188 +129 963 +630 820 +509 300 +237 822 +373 255 +838 277 +395 153 +692 400 +103 227 +218 518 +384 447 +931 315 +396 813 +389 324 +640 502 +287 299 +297 780 +977 376 +512 516 +219 212 +555 329 +398 810 +289 486 +798 485 +598 416 +49 952 +572 894 +697 358 +770 21 +725 647 +542 44 +214 683 +887 361 +45 814 +94 231 +282 8 +82 165 +319 496 +626 699 +146 852 +541 459 +874 535 +725 314 +777 944 +554 306 +208 459 +787 637 +976 447 +912 408 +444 107 +3 962 +301 565 +164 407 +437 857 +652 317 +764 98 +41 818 +737 600 +176 288 +136 902 +128 567 +394 190 +235 749 +42 908 +824 276 +684 748 +979 592 +568 393 +367 363 +52 163 +642 983 +335 179 +126 16 +130 478 +583 259 +129 868 +752 295 +167 596 +856 71 +640 622 +770 864 +431 644 +195 5 +448 365 +701 429 +952 64 +880 854 +168 770 +79 88 +961 157 +472 368 +217 421 +709 719 +147 271 +296 975 +909 816 +764 962 +251 535 +878 438 +753 696 +570 881 +253 318 +666 45 +931 52 +433 496 +810 313 +678 138 +123 334 +212 988 +0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_2_1000_1000_1 b/scripts/Knapsack/Data/knapPI_2_1000_1000_1 new file mode 100644 index 0000000..f318ce1 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_2_1000_1000_1 @@ -0,0 +1,1002 @@ +1000 5002 +482 485 +257 326 +286 248 +517 421 +404 322 +713 795 +45 43 +924 845 +873 955 +160 252 +1 9 +838 901 +40 122 +58 94 +676 738 +627 574 +766 715 +862 882 +405 367 +923 984 +379 299 +461 433 +612 682 +133 72 +813 874 +97 138 +908 856 +165 145 +996 995 +623 529 +220 199 +298 277 +157 97 +723 719 +144 242 +48 107 +129 122 +148 70 +35 98 +644 600 +632 645 +272 267 +1040 972 +977 895 +312 213 +778 748 +567 487 +965 923 +1 29 +616 674 +569 540 +628 554 +493 467 +76 46 +733 710 +575 553 +288 191 +775 724 +723 730 +912 988 +64 90 +354 340 +565 549 +210 196 +922 865 +775 678 +566 570 +934 936 +626 722 +742 651 +194 123 +485 431 +483 508 +617 585 +876 853 +653 642 +896 992 +652 725 +220 286 +727 812 +900 859 +563 663 +56 88 +157 179 +280 187 +537 619 +284 261 +920 846 +124 192 +239 261 +459 514 +931 886 +504 530 +910 849 +382 294 +795 799 +485 391 +351 330 +289 298 +865 790 +250 275 +738 826 +75 72 +788 866 +947 951 +651 748 +595 685 +993 956 +663 564 +265 183 +338 400 +637 721 +206 207 +328 323 +618 611 +64 116 +139 109 +806 795 +412 343 +912 862 +715 685 +1 10 +929 881 +1025 984 +410 403 +273 360 +507 449 +450 541 +174 272 +882 877 +427 359 +787 707 +355 308 +734 770 +1 30 +248 208 +397 311 +159 100 +874 939 +449 422 +857 785 +286 370 +976 989 +908 969 +103 143 +1071 972 +1 28 +117 61 +697 638 +424 348 +439 347 +74 66 +442 391 +568 638 +195 295 +854 826 +281 196 +433 449 +845 855 +224 143 +487 487 +181 140 +496 564 +690 615 +124 135 +575 564 +374 360 +766 793 +149 163 +776 859 +793 760 +674 711 +696 662 +90 159 +732 660 +214 268 +935 948 +228 315 +619 676 +349 341 +734 689 +964 894 +644 706 +484 490 +491 478 +628 671 +1009 932 +944 899 +315 237 +92 187 +554 472 +757 772 +88 98 +952 906 +818 911 +628 635 +316 225 +818 823 +255 164 +432 343 +763 732 +490 502 +721 740 +587 576 +530 612 +992 902 +491 454 +343 411 +880 973 +645 703 +761 850 +152 77 +241 220 +727 802 +352 403 +246 181 +1 10 +479 525 +958 919 +749 668 +551 527 +538 462 +319 291 +580 605 +501 457 +487 405 +349 417 +252 279 +731 685 +637 596 +339 307 +257 224 +271 322 +740 840 +1002 975 +404 401 +190 91 +254 327 +277 330 +100 182 +648 603 +810 793 +535 615 +702 733 +855 864 +76 16 +773 863 +917 987 +279 306 +123 34 +922 840 +613 700 +658 706 +705 787 +101 105 +807 834 +883 798 +358 310 +634 609 +786 690 +618 561 +644 579 +141 60 +466 388 +340 309 +495 407 +283 200 +352 313 +886 970 +95 33 +291 273 +217 277 +1007 997 +1 40 +219 227 +764 860 +1025 940 +600 608 +895 990 +690 590 +738 806 +1 52 +772 801 +727 764 +774 710 +340 386 +503 593 +1 50 +432 494 +228 156 +993 936 +1058 965 +130 86 +821 723 +189 184 +943 868 +343 340 +404 412 +560 487 +196 209 +418 346 +782 860 +314 307 +59 95 +778 821 +979 941 +828 821 +584 587 +122 201 +741 665 +566 527 +760 812 +385 424 +395 459 +250 343 +789 836 +492 506 +261 179 +914 916 +380 430 +537 596 +731 808 +361 269 +473 512 +737 811 +708 685 +635 567 +804 776 +827 855 +695 718 +756 853 +57 97 +178 146 +688 746 +1 15 +871 965 +415 512 +510 480 +1057 958 +764 665 +193 191 +905 964 +583 515 +696 606 +887 822 +444 536 +741 693 +12 19 +313 335 +81 101 +828 922 +354 294 +981 910 +499 410 +283 250 +545 546 +635 729 +540 609 +689 720 +946 976 +730 759 +703 798 +14 74 +644 648 +241 299 +793 785 +912 846 +461 390 +801 897 +424 416 +744 837 +272 247 +338 293 +193 144 +987 938 +432 467 +505 480 +944 955 +653 665 +38 26 +468 564 +461 449 +1 26 +576 521 +329 301 +274 321 +701 613 +432 388 +851 879 +915 990 +137 188 +927 963 +903 820 +373 300 +770 822 +160 255 +285 277 +231 153 +366 400 +317 227 +423 518 +420 447 +216 315 +772 813 +271 324 +566 502 +243 299 +725 780 +390 376 +491 516 +225 212 +392 329 +781 810 +434 486 +535 485 +368 416 +938 952 +946 894 +353 358 +1 21 +707 647 +143 44 +630 683 +364 361 +822 814 +147 231 +54 8 +91 165 +431 496 +606 699 +917 852 +553 459 +473 535 +222 314 +954 944 +369 306 +413 459 +717 637 +491 447 +447 408 +44 107 +994 962 +518 565 +448 407 +931 857 +369 317 +181 98 +815 818 +655 600 +267 288 +960 902 +611 567 +271 190 +771 749 +993 908 +359 276 +810 748 +563 592 +360 393 +264 363 +199 163 +1074 983 +131 179 +41 16 +423 478 +197 259 +779 868 +344 295 +536 596 +140 71 +669 622 +938 864 +715 644 +67 5 +321 365 +434 429 +19 64 +928 854 +759 770 +178 88 +160 157 +277 368 +467 421 +653 719 +330 271 +966 975 +817 816 +1045 962 +508 535 +492 438 +743 696 +884 881 +259 318 +56 45 +1 52 +421 496 +270 313 +99 138 +429 334 +1004 988 +512 508 +702 770 +657 751 +862 780 +516 441 +246 207 +592 516 +641 674 +390 408 +831 920 +522 573 +611 634 +825 878 +929 990 +734 826 +718 696 +883 800 +355 411 +426 422 +668 707 +235 334 +1080 986 +397 494 +137 150 +648 562 +342 380 +799 832 +1067 979 +313 376 +452 511 +441 414 +214 160 +1059 982 +260 238 +579 490 +897 899 +316 251 +526 526 +909 897 +139 39 +634 657 +384 452 +577 538 +840 831 +509 460 +262 185 +934 934 +513 440 +556 490 +97 168 +107 71 +937 977 +370 458 +193 204 +802 803 +134 139 +390 399 +439 420 +1034 991 +636 578 +1008 972 +191 177 +429 398 +445 348 +483 496 +347 276 +769 825 +540 614 +212 121 +789 730 +317 341 +381 284 +714 698 +24 17 +570 546 +771 672 +1052 974 +776 866 +290 377 +470 559 +367 340 +626 527 +879 779 +688 761 +553 483 +112 92 +440 390 +510 583 +741 661 +473 391 +289 336 +574 661 +85 125 +36 89 +362 275 +310 359 +129 178 +763 780 +31 42 +69 5 +470 380 +739 772 +726 816 +57 9 +476 484 +498 545 +669 589 +112 157 +934 901 +854 777 +112 74 +246 247 +1 55 +481 479 +883 785 +1051 958 +763 680 +417 393 +900 944 +573 596 +601 619 +588 611 +900 852 +327 283 +199 299 +847 766 +240 312 +862 826 +635 726 +680 733 +806 805 +767 679 +495 403 +870 964 +259 337 +476 541 +512 478 +467 369 +1001 946 +798 821 +819 833 +835 837 +502 490 +119 37 +652 594 +82 129 +242 258 +215 246 +291 362 +687 755 +550 504 +1 71 +249 177 +203 176 +865 803 +189 237 +758 677 +90 33 +188 115 +621 597 +807 769 +481 536 +1031 956 +349 341 +222 184 +260 234 +551 569 +245 216 +631 537 +183 84 +873 810 +656 657 +5 33 +137 159 +579 520 +656 668 +373 287 +232 229 +352 374 +428 474 +598 672 +943 915 +582 511 +120 123 +573 569 +218 199 +347 396 +628 715 +1 59 +642 610 +959 917 +983 927 +186 270 +60 117 +513 516 +143 215 +234 216 +290 237 +597 615 +452 499 +521 477 +837 760 +267 285 +20 56 +1027 966 +690 622 +235 221 +199 194 +186 91 +374 347 +244 252 +424 473 +438 516 +385 385 +337 357 +945 958 +686 665 +698 792 +16 64 +464 420 +655 671 +911 968 +839 877 +144 177 +535 523 +65 139 +230 152 +806 732 +312 246 +578 565 +699 740 +817 902 +105 17 +886 973 +360 298 +658 611 +53 32 +1 11 +319 337 +36 136 +879 889 +595 522 +721 805 +80 28 +981 931 +838 757 +654 609 +480 544 +973 905 +647 595 +243 246 +152 113 +183 175 +140 156 +263 244 +856 883 +338 265 +792 883 +403 462 +560 485 +238 272 +214 204 +1011 984 +453 409 +330 398 +819 909 +469 370 +882 882 +279 214 +811 766 +82 35 +341 421 +271 271 +397 370 +876 848 +128 50 +1016 976 +243 270 +843 796 +949 963 +451 379 +1091 991 +594 551 +867 897 +353 307 +471 421 +100 74 +401 388 +591 559 +884 980 +607 615 +651 681 +209 231 +133 207 +741 818 +372 331 +950 979 +403 445 +419 348 +780 724 +345 401 +618 646 +766 668 +335 242 +288 302 +795 861 +777 830 +117 77 +541 441 +499 589 +1025 990 +217 189 +799 868 +944 996 +329 363 +232 237 +367 420 +552 565 +220 214 +353 333 +811 726 +176 175 +35 58 +548 625 +1 66 +142 169 +400 475 +298 204 +27 90 +421 496 +40 1 +462 474 +359 449 +299 252 +395 332 +382 287 +206 189 +980 889 +1 63 +285 378 +109 206 +813 897 +219 230 +361 382 +601 575 +155 60 +442 529 +405 477 +253 290 +57 89 +894 961 +548 461 +763 702 +542 532 +704 680 +44 53 +545 642 +1018 1000 +803 891 +730 822 +59 152 +423 324 +590 633 +266 267 +325 381 +307 272 +422 506 +403 419 +524 461 +613 526 +1033 978 +403 468 +820 729 +777 795 +631 581 +298 383 +302 226 +505 421 +461 386 +351 273 +556 484 +638 676 +152 107 +236 229 +831 902 +882 962 +38 105 +100 84 +1006 991 +661 701 +596 689 +748 655 +528 600 +587 538 +492 499 +783 881 +1017 981 +546 473 +368 383 +618 679 +662 573 +563 589 +553 480 +161 145 +612 624 +926 923 +972 915 +249 232 +948 974 +662 735 +735 678 +682 640 +722 644 +146 212 +75 123 +276 253 +890 943 +1 18 +1007 916 +302 327 +607 640 +646 615 +488 470 +565 655 +239 288 +448 401 +906 840 +564 633 +647 707 +339 424 +757 682 +213 194 +829 855 +229 190 +703 728 +257 178 +255 275 +123 88 +321 367 +517 544 +768 738 +1040 963 +439 460 +282 266 +739 727 +128 33 +471 442 +714 628 +467 384 +298 244 +411 482 +760 765 +435 446 +245 247 +865 913 +658 560 +457 528 +694 594 +882 935 +415 462 +555 621 +705 660 +525 564 +276 302 +871 936 +582 592 +639 724 +181 118 +200 299 +201 251 +35 129 +5 96 +85 167 +239 169 +359 381 +948 976 +771 767 +804 837 +457 407 +284 203 +485 387 +803 735 +629 706 +358 335 +13 40 +808 821 +68 131 +96 159 +956 978 +101 53 +767 849 +577 478 +1 19 +278 230 +388 453 +318 336 +847 931 +592 588 +494 449 +615 566 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_2_100_1000_1 b/scripts/Knapsack/Data/knapPI_2_100_1000_1 new file mode 100644 index 0000000..1e85ecf --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_2_100_1000_1 @@ -0,0 +1,102 @@ +100 995 +482 485 +257 326 +286 248 +517 421 +404 322 +713 795 +45 43 +924 845 +873 955 +160 252 +1 9 +838 901 +40 122 +58 94 +676 738 +627 574 +766 715 +862 882 +405 367 +923 984 +379 299 +461 433 +612 682 +133 72 +813 874 +97 138 +908 856 +165 145 +996 995 +623 529 +220 199 +298 277 +157 97 +723 719 +144 242 +48 107 +129 122 +148 70 +35 98 +644 600 +632 645 +272 267 +1040 972 +977 895 +312 213 +778 748 +567 487 +965 923 +1 29 +616 674 +569 540 +628 554 +493 467 +76 46 +733 710 +575 553 +288 191 +775 724 +723 730 +912 988 +64 90 +354 340 +565 549 +210 196 +922 865 +775 678 +566 570 +934 936 +626 722 +742 651 +194 123 +485 431 +483 508 +617 585 +876 853 +653 642 +896 992 +652 725 +220 286 +727 812 +900 859 +563 663 +56 88 +157 179 +280 187 +537 619 +284 261 +920 846 +124 192 +239 261 +459 514 +931 886 +504 530 +910 849 +382 294 +795 799 +485 391 +351 330 +289 298 +865 790 +0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_2_2000_1000_1 b/scripts/Knapsack/Data/knapPI_2_2000_1000_1 new file mode 100644 index 0000000..af42377 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_2_2000_1000_1 @@ -0,0 +1,2002 @@ +2000 10011 +482 485 +257 326 +286 248 +517 421 +404 322 +713 795 +45 43 +924 845 +873 955 +160 252 +1 9 +838 901 +40 122 +58 94 +676 738 +627 574 +766 715 +862 882 +405 367 +923 984 +379 299 +461 433 +612 682 +133 72 +813 874 +97 138 +908 856 +165 145 +996 995 +623 529 +220 199 +298 277 +157 97 +723 719 +144 242 +48 107 +129 122 +148 70 +35 98 +644 600 +632 645 +272 267 +1040 972 +977 895 +312 213 +778 748 +567 487 +965 923 +1 29 +616 674 +569 540 +628 554 +493 467 +76 46 +733 710 +575 553 +288 191 +775 724 +723 730 +912 988 +64 90 +354 340 +565 549 +210 196 +922 865 +775 678 +566 570 +934 936 +626 722 +742 651 +194 123 +485 431 +483 508 +617 585 +876 853 +653 642 +896 992 +652 725 +220 286 +727 812 +900 859 +563 663 +56 88 +157 179 +280 187 +537 619 +284 261 +920 846 +124 192 +239 261 +459 514 +931 886 +504 530 +910 849 +382 294 +795 799 +485 391 +351 330 +289 298 +865 790 +250 275 +738 826 +75 72 +788 866 +947 951 +651 748 +595 685 +993 956 +663 564 +265 183 +338 400 +637 721 +206 207 +328 323 +618 611 +64 116 +139 109 +806 795 +412 343 +912 862 +715 685 +1 10 +929 881 +1025 984 +410 403 +273 360 +507 449 +450 541 +174 272 +882 877 +427 359 +787 707 +355 308 +734 770 +1 30 +248 208 +397 311 +159 100 +874 939 +449 422 +857 785 +286 370 +976 989 +908 969 +103 143 +1071 972 +1 28 +117 61 +697 638 +424 348 +439 347 +74 66 +442 391 +568 638 +195 295 +854 826 +281 196 +433 449 +845 855 +224 143 +487 487 +181 140 +496 564 +690 615 +124 135 +575 564 +374 360 +766 793 +149 163 +776 859 +793 760 +674 711 +696 662 +90 159 +732 660 +214 268 +935 948 +228 315 +619 676 +349 341 +734 689 +964 894 +644 706 +484 490 +491 478 +628 671 +1009 932 +944 899 +315 237 +92 187 +554 472 +757 772 +88 98 +952 906 +818 911 +628 635 +316 225 +818 823 +255 164 +432 343 +763 732 +490 502 +721 740 +587 576 +530 612 +992 902 +491 454 +343 411 +880 973 +645 703 +761 850 +152 77 +241 220 +727 802 +352 403 +246 181 +1 10 +479 525 +958 919 +749 668 +551 527 +538 462 +319 291 +580 605 +501 457 +487 405 +349 417 +252 279 +731 685 +637 596 +339 307 +257 224 +271 322 +740 840 +1002 975 +404 401 +190 91 +254 327 +277 330 +100 182 +648 603 +810 793 +535 615 +702 733 +855 864 +76 16 +773 863 +917 987 +279 306 +123 34 +922 840 +613 700 +658 706 +705 787 +101 105 +807 834 +883 798 +358 310 +634 609 +786 690 +618 561 +644 579 +141 60 +466 388 +340 309 +495 407 +283 200 +352 313 +886 970 +95 33 +291 273 +217 277 +1007 997 +1 40 +219 227 +764 860 +1025 940 +600 608 +895 990 +690 590 +738 806 +1 52 +772 801 +727 764 +774 710 +340 386 +503 593 +1 50 +432 494 +228 156 +993 936 +1058 965 +130 86 +821 723 +189 184 +943 868 +343 340 +404 412 +560 487 +196 209 +418 346 +782 860 +314 307 +59 95 +778 821 +979 941 +828 821 +584 587 +122 201 +741 665 +566 527 +760 812 +385 424 +395 459 +250 343 +789 836 +492 506 +261 179 +914 916 +380 430 +537 596 +731 808 +361 269 +473 512 +737 811 +708 685 +635 567 +804 776 +827 855 +695 718 +756 853 +57 97 +178 146 +688 746 +1 15 +871 965 +415 512 +510 480 +1057 958 +764 665 +193 191 +905 964 +583 515 +696 606 +887 822 +444 536 +741 693 +12 19 +313 335 +81 101 +828 922 +354 294 +981 910 +499 410 +283 250 +545 546 +635 729 +540 609 +689 720 +946 976 +730 759 +703 798 +14 74 +644 648 +241 299 +793 785 +912 846 +461 390 +801 897 +424 416 +744 837 +272 247 +338 293 +193 144 +987 938 +432 467 +505 480 +944 955 +653 665 +38 26 +468 564 +461 449 +1 26 +576 521 +329 301 +274 321 +701 613 +432 388 +851 879 +915 990 +137 188 +927 963 +903 820 +373 300 +770 822 +160 255 +285 277 +231 153 +366 400 +317 227 +423 518 +420 447 +216 315 +772 813 +271 324 +566 502 +243 299 +725 780 +390 376 +491 516 +225 212 +392 329 +781 810 +434 486 +535 485 +368 416 +938 952 +946 894 +353 358 +1 21 +707 647 +143 44 +630 683 +364 361 +822 814 +147 231 +54 8 +91 165 +431 496 +606 699 +917 852 +553 459 +473 535 +222 314 +954 944 +369 306 +413 459 +717 637 +491 447 +447 408 +44 107 +994 962 +518 565 +448 407 +931 857 +369 317 +181 98 +815 818 +655 600 +267 288 +960 902 +611 567 +271 190 +771 749 +993 908 +359 276 +810 748 +563 592 +360 393 +264 363 +199 163 +1074 983 +131 179 +41 16 +423 478 +197 259 +779 868 +344 295 +536 596 +140 71 +669 622 +938 864 +715 644 +67 5 +321 365 +434 429 +19 64 +928 854 +759 770 +178 88 +160 157 +277 368 +467 421 +653 719 +330 271 +966 975 +817 816 +1045 962 +508 535 +492 438 +743 696 +884 881 +259 318 +56 45 +1 52 +421 496 +270 313 +99 138 +429 334 +1004 988 +512 508 +702 770 +657 751 +862 780 +516 441 +246 207 +592 516 +641 674 +390 408 +831 920 +522 573 +611 634 +825 878 +929 990 +734 826 +718 696 +883 800 +355 411 +426 422 +668 707 +235 334 +1080 986 +397 494 +137 150 +648 562 +342 380 +799 832 +1067 979 +313 376 +452 511 +441 414 +214 160 +1059 982 +260 238 +579 490 +897 899 +316 251 +526 526 +909 897 +139 39 +634 657 +384 452 +577 538 +840 831 +509 460 +262 185 +934 934 +513 440 +556 490 +97 168 +107 71 +937 977 +370 458 +193 204 +802 803 +134 139 +390 399 +439 420 +1034 991 +636 578 +1008 972 +191 177 +429 398 +445 348 +483 496 +347 276 +769 825 +540 614 +212 121 +789 730 +317 341 +381 284 +714 698 +24 17 +570 546 +771 672 +1052 974 +776 866 +290 377 +470 559 +367 340 +626 527 +879 779 +688 761 +553 483 +112 92 +440 390 +510 583 +741 661 +473 391 +289 336 +574 661 +85 125 +36 89 +362 275 +310 359 +129 178 +763 780 +31 42 +69 5 +470 380 +739 772 +726 816 +57 9 +476 484 +498 545 +669 589 +112 157 +934 901 +854 777 +112 74 +246 247 +1 55 +481 479 +883 785 +1051 958 +763 680 +417 393 +900 944 +573 596 +601 619 +588 611 +900 852 +327 283 +199 299 +847 766 +240 312 +862 826 +635 726 +680 733 +806 805 +767 679 +495 403 +870 964 +259 337 +476 541 +512 478 +467 369 +1001 946 +798 821 +819 833 +835 837 +502 490 +119 37 +652 594 +82 129 +242 258 +215 246 +291 362 +687 755 +550 504 +1 71 +249 177 +203 176 +865 803 +189 237 +758 677 +90 33 +188 115 +621 597 +807 769 +481 536 +1031 956 +349 341 +222 184 +260 234 +551 569 +245 216 +631 537 +183 84 +873 810 +656 657 +5 33 +137 159 +579 520 +656 668 +373 287 +232 229 +352 374 +428 474 +598 672 +943 915 +582 511 +120 123 +573 569 +218 199 +347 396 +628 715 +1 59 +642 610 +959 917 +983 927 +186 270 +60 117 +513 516 +143 215 +234 216 +290 237 +597 615 +452 499 +521 477 +837 760 +267 285 +20 56 +1027 966 +690 622 +235 221 +199 194 +186 91 +374 347 +244 252 +424 473 +438 516 +385 385 +337 357 +945 958 +686 665 +698 792 +16 64 +464 420 +655 671 +911 968 +839 877 +144 177 +535 523 +65 139 +230 152 +806 732 +312 246 +578 565 +699 740 +817 902 +105 17 +886 973 +360 298 +658 611 +53 32 +1 11 +319 337 +36 136 +879 889 +595 522 +721 805 +80 28 +981 931 +838 757 +654 609 +480 544 +973 905 +647 595 +243 246 +152 113 +183 175 +140 156 +263 244 +856 883 +338 265 +792 883 +403 462 +560 485 +238 272 +214 204 +1011 984 +453 409 +330 398 +819 909 +469 370 +882 882 +279 214 +811 766 +82 35 +341 421 +271 271 +397 370 +876 848 +128 50 +1016 976 +243 270 +843 796 +949 963 +451 379 +1091 991 +594 551 +867 897 +353 307 +471 421 +100 74 +401 388 +591 559 +884 980 +607 615 +651 681 +209 231 +133 207 +741 818 +372 331 +950 979 +403 445 +419 348 +780 724 +345 401 +618 646 +766 668 +335 242 +288 302 +795 861 +777 830 +117 77 +541 441 +499 589 +1025 990 +217 189 +799 868 +944 996 +329 363 +232 237 +367 420 +552 565 +220 214 +353 333 +811 726 +176 175 +35 58 +548 625 +1 66 +142 169 +400 475 +298 204 +27 90 +421 496 +40 1 +462 474 +359 449 +299 252 +395 332 +382 287 +206 189 +980 889 +1 63 +285 378 +109 206 +813 897 +219 230 +361 382 +601 575 +155 60 +442 529 +405 477 +253 290 +57 89 +894 961 +548 461 +763 702 +542 532 +704 680 +44 53 +545 642 +1018 1000 +803 891 +730 822 +59 152 +423 324 +590 633 +266 267 +325 381 +307 272 +422 506 +403 419 +524 461 +613 526 +1033 978 +403 468 +820 729 +777 795 +631 581 +298 383 +302 226 +505 421 +461 386 +351 273 +556 484 +638 676 +152 107 +236 229 +831 902 +882 962 +38 105 +100 84 +1006 991 +661 701 +596 689 +748 655 +528 600 +587 538 +492 499 +783 881 +1017 981 +546 473 +368 383 +618 679 +662 573 +563 589 +553 480 +161 145 +612 624 +926 923 +972 915 +249 232 +948 974 +662 735 +735 678 +682 640 +722 644 +146 212 +75 123 +276 253 +890 943 +1 18 +1007 916 +302 327 +607 640 +646 615 +488 470 +565 655 +239 288 +448 401 +906 840 +564 633 +647 707 +339 424 +757 682 +213 194 +829 855 +229 190 +703 728 +257 178 +255 275 +123 88 +321 367 +517 544 +768 738 +1040 963 +439 460 +282 266 +739 727 +128 33 +471 442 +714 628 +467 384 +298 244 +411 482 +760 765 +435 446 +245 247 +865 913 +658 560 +457 528 +694 594 +882 935 +415 462 +555 621 +705 660 +525 564 +276 302 +871 936 +582 592 +639 724 +181 118 +200 299 +201 251 +35 129 +5 96 +85 167 +239 169 +359 381 +948 976 +771 767 +804 837 +457 407 +284 203 +485 387 +803 735 +629 706 +358 335 +13 40 +808 821 +68 131 +96 159 +956 978 +101 53 +767 849 +577 478 +1 19 +278 230 +388 453 +318 336 +847 931 +592 588 +494 449 +615 566 +265 272 +806 883 +754 731 +94 80 +113 213 +203 177 +896 872 +712 626 +1000 940 +69 150 +279 379 +847 833 +509 517 +686 724 +946 973 +652 581 +872 839 +237 272 +314 412 +789 839 +440 492 +526 553 +714 718 +791 738 +816 839 +385 390 +557 588 +562 523 +715 630 +815 770 +752 746 +1 49 +280 369 +498 537 +116 115 +155 215 +872 971 +572 602 +551 551 +1 40 +399 494 +306 252 +153 158 +81 72 +84 177 +755 667 +504 483 +724 815 +94 19 +725 745 +266 339 +660 614 +263 302 +341 319 +635 670 +519 513 +647 566 +24 27 +259 322 +707 645 +162 210 +925 841 +830 925 +600 521 +931 975 +177 269 +862 929 +437 478 +918 970 +737 684 +227 231 +595 673 +343 348 +194 232 +683 727 +616 597 +401 397 +608 539 +923 907 +928 892 +731 699 +435 408 +265 361 +828 789 +583 529 +275 190 +812 880 +212 236 +659 715 +725 718 +348 439 +774 814 +845 902 +593 658 +393 410 +511 412 +5 90 +689 678 +916 951 +120 37 +624 593 +781 737 +174 211 +156 134 +769 847 +433 490 +57 95 +389 435 +822 737 +760 860 +360 310 +545 548 +991 984 +669 660 +142 86 +707 635 +935 941 +156 56 +357 372 +630 650 +1041 964 +734 735 +730 682 +166 151 +223 283 +834 773 +648 643 +918 898 +781 817 +362 269 +760 731 +454 507 +853 841 +294 207 +779 752 +407 318 +86 126 +182 153 +49 101 +623 560 +786 743 +765 816 +981 980 +29 1 +69 82 +914 886 +448 377 +476 465 +752 753 +847 842 +609 547 +660 580 +700 754 +1 37 +616 548 +963 896 +735 656 +615 537 +143 78 +582 540 +525 597 +253 314 +877 845 +321 361 +988 930 +562 654 +866 841 +754 810 +193 98 +846 814 +977 898 +220 237 +310 236 +375 397 +512 468 +112 160 +176 168 +262 189 +123 123 +826 783 +1063 991 +839 775 +505 565 +838 906 +680 604 +229 233 +759 693 +188 209 +241 279 +166 231 +773 675 +324 370 +777 814 +285 276 +200 238 +663 710 +916 931 +833 879 +433 492 +168 81 +386 347 +360 417 +612 582 +755 801 +282 195 +474 403 +215 247 +351 356 +571 627 +838 858 +722 803 +277 236 +521 572 +585 485 +526 586 +808 748 +291 235 +838 859 +793 788 +394 345 +801 861 +395 342 +783 779 +555 595 +910 963 +195 260 +315 366 +796 835 +687 733 +808 834 +357 442 +690 773 +974 880 +928 873 +722 793 +164 173 +394 402 +38 60 +688 628 +1 19 +146 146 +741 685 +88 138 +636 593 +265 202 +590 500 +66 89 +508 433 +133 63 +494 514 +785 865 +433 393 +364 269 +129 111 +659 614 +330 272 +950 973 +673 609 +285 236 +493 496 +120 24 +795 871 +186 227 +391 420 +933 850 +112 127 +186 170 +190 224 +714 722 +267 189 +548 597 +346 286 +1 22 +958 957 +576 536 +311 221 +292 281 +261 238 +622 531 +472 449 +714 735 +575 670 +667 646 +297 272 +546 605 +390 394 +595 508 +570 537 +893 955 +408 477 +947 969 +697 692 +896 963 +914 829 +623 638 +122 206 +229 185 +210 187 +36 129 +266 300 +207 114 +391 305 +174 199 +897 916 +802 839 +966 899 +464 452 +163 185 +552 561 +825 848 +167 191 +864 830 +885 860 +952 873 +574 649 +632 591 +915 974 +1037 974 +471 452 +364 397 +331 350 +671 597 +34 13 +405 392 +273 343 +844 756 +438 387 +888 924 +174 188 +1 68 +581 552 +112 166 +406 435 +3 14 +782 797 +186 254 +228 300 +483 431 +346 367 +220 197 +237 233 +249 149 +51 62 +1 38 +106 69 +430 425 +855 810 +834 878 +484 503 +240 308 +781 798 +394 437 +805 798 +23 36 +527 583 +418 412 +182 195 +783 878 +347 388 +478 438 +435 532 +18 3 +332 268 +373 417 +282 277 +273 229 +486 445 +358 380 +884 974 +329 248 +491 433 +1039 1000 +781 874 +889 939 +813 760 +538 473 +721 811 +810 766 +236 306 +558 556 +527 521 +377 364 +467 460 +230 136 +537 458 +839 784 +623 648 +693 783 +922 960 +42 137 +524 591 +845 875 +503 440 +310 263 +91 40 +916 835 +863 943 +726 749 +214 263 +621 597 +59 5 +1029 999 +118 161 +1 35 +933 891 +377 459 +926 996 +675 592 +1 54 +1080 985 +444 401 +259 298 +383 459 +144 77 +617 611 +169 159 +392 467 +821 737 +887 895 +135 49 +482 382 +347 285 +326 388 +1048 972 +353 265 +691 729 +822 810 +1056 973 +867 818 +349 295 +566 532 +126 58 +758 736 +113 187 +923 896 +1063 998 +914 997 +564 476 +221 259 +536 475 +465 494 +124 130 +222 151 +669 639 +774 855 +565 480 +431 478 +471 386 +602 672 +371 361 +821 894 +447 460 +122 148 +749 660 +706 628 +367 329 +898 975 +17 1 +584 507 +815 750 +53 109 +878 915 +735 700 +38 75 +880 896 +233 229 +1 85 +147 144 +595 536 +841 919 +584 516 +425 473 +1 25 +1 25 +682 611 +22 44 +798 722 +954 980 +615 563 +585 672 +976 914 +448 541 +917 882 +178 142 +346 259 +113 35 +641 543 +652 689 +819 721 +235 142 +509 530 +602 503 +519 450 +305 248 +608 599 +911 919 +546 636 +205 181 +799 873 +112 154 +440 427 +669 604 +313 313 +441 363 +601 594 +815 813 +898 829 +133 49 +808 791 +463 554 +471 499 +215 226 +325 345 +402 432 +671 758 +113 64 +933 843 +585 637 +945 941 +891 965 +502 448 +798 857 +982 968 +258 351 +691 758 +307 351 +901 980 +670 662 +338 357 +921 914 +642 548 +793 723 +1 23 +214 170 +326 351 +35 113 +755 783 +747 766 +497 527 +233 206 +551 644 +348 258 +921 861 +675 728 +122 69 +173 128 +397 392 +81 145 +112 51 +179 112 +245 253 +300 340 +1027 932 +832 817 +970 965 +493 480 +633 724 +812 839 +549 500 +726 746 +767 811 +450 373 +641 605 +351 252 +162 172 +388 394 +229 177 +84 98 +325 377 +518 486 +792 855 +382 290 +146 130 +426 355 +885 842 +255 233 +81 101 +671 686 +676 736 +844 930 +748 700 +92 69 +696 607 +949 879 +904 916 +1037 960 +345 408 +681 679 +130 138 +123 185 +684 782 +9 49 +464 453 +551 630 +364 429 +845 853 +450 545 +645 651 +853 765 +155 159 +1007 1000 +120 179 +743 717 +816 885 +71 32 +833 838 +148 186 +486 470 +270 185 +836 921 +385 376 +954 986 +852 934 +90 171 +552 645 +1 46 +762 681 +1 43 +231 234 +99 103 +536 496 +486 389 +945 931 +639 579 +164 132 +966 908 +679 772 +736 677 +425 343 +714 703 +134 139 +337 344 +418 387 +840 909 +471 539 +361 304 +745 655 +374 378 +153 92 +841 862 +428 411 +420 362 +383 397 +331 290 +182 152 +687 611 +188 173 +226 137 +982 946 +432 365 +410 475 +971 982 +832 920 +710 802 +1 66 +711 778 +715 744 +535 464 +399 313 +401 341 +620 685 +339 331 +150 85 +741 676 +89 91 +535 534 +229 166 +124 51 +970 966 +849 841 +558 625 +173 114 +1 16 +29 113 +800 826 +581 506 +794 738 +657 564 +364 455 +711 735 +283 264 +526 548 +717 738 +900 853 +557 575 +495 569 +316 365 +599 620 +340 264 +144 193 +1 21 +285 373 +168 84 +167 250 +190 288 +86 132 +180 151 +337 419 +522 521 +907 974 +601 655 +690 648 +830 737 +398 298 +227 187 +1017 981 +870 965 +979 954 +149 166 +330 248 +655 636 +565 560 +624 563 +11 24 +813 896 +821 803 +1 16 +291 274 +809 714 +406 449 +192 229 +188 280 +494 423 +769 868 +115 124 +945 970 +312 231 +859 935 +809 808 +61 23 +110 210 +149 88 +192 151 +742 770 +600 555 +580 613 +771 866 +230 223 +258 303 +383 305 +312 306 +951 900 +962 964 +467 397 +966 898 +63 59 +571 628 +182 225 +473 537 +624 612 +619 633 +275 314 +551 478 +1071 981 +868 904 +776 819 +187 108 +245 179 +196 152 +686 598 +321 349 +100 80 +796 762 +292 314 +417 513 +293 205 +510 584 +731 652 +983 894 +149 198 +220 143 +601 671 +304 302 +575 611 +631 631 +533 526 +533 526 +439 403 +141 231 +794 830 +242 283 +772 864 +728 755 +62 159 +141 220 +454 447 +892 800 +880 833 +804 805 +724 791 +499 412 +850 857 +476 408 +859 895 +313 360 +874 827 +875 971 +909 961 +431 519 +432 335 +329 238 +935 883 +204 222 +827 886 +764 708 +376 475 +933 876 +69 123 +76 127 +310 384 +798 745 +311 284 +388 429 +776 685 +593 512 +577 503 +576 599 +925 983 +439 462 +1064 992 +236 270 +393 491 +267 282 +766 831 +146 167 +28 115 +579 661 +539 564 +902 934 +527 608 +586 513 +1 53 +725 659 +706 646 +120 164 +752 763 +828 825 +887 949 +321 355 +775 811 +188 164 +766 851 +253 289 +483 392 +130 224 +419 460 +886 903 +440 347 +579 638 +45 101 +666 587 +736 797 +792 881 +219 210 +194 243 +938 969 +225 298 +161 253 +576 593 +439 453 +663 657 +172 72 +225 222 +402 319 +1 61 +750 694 +448 384 +739 801 +218 136 +522 536 +1012 958 +557 647 +610 526 +1 28 +999 904 +484 509 +922 884 +539 565 +635 601 +417 323 +615 522 +149 192 +66 103 +483 451 +903 867 +555 602 +874 783 +346 311 +1027 994 +187 172 +1 51 +332 389 +193 237 +796 721 +561 597 +417 492 +248 331 +358 380 +190 259 +653 726 +54 55 +496 501 +395 459 +729 790 +1 4 +715 634 +170 117 +666 601 +711 808 +457 544 +504 542 +598 590 +829 827 +864 817 +657 617 +1 32 +815 879 +593 692 +709 685 +90 88 +820 911 +553 546 +528 580 +948 997 +1018 937 +1069 988 +433 351 +563 661 +617 630 +367 360 +897 908 +263 203 +545 479 +270 251 +212 162 +967 905 +227 167 +779 862 +346 369 +86 181 +684 765 +291 251 +992 909 +712 645 +664 568 +896 847 +547 538 +466 540 +193 99 +438 423 +323 246 +88 165 +549 544 +120 52 +218 131 +273 372 +500 471 +651 625 +696 684 +432 378 +542 534 +46 73 +458 540 +639 671 +207 127 +507 412 +1067 972 +825 823 +716 663 +755 784 +608 588 +514 496 +209 170 +133 153 +209 199 +216 152 +355 258 +208 283 +305 289 +616 608 +428 463 +157 180 +404 329 +271 221 +266 294 +119 125 +534 625 +376 427 +712 796 +131 151 +883 867 +214 122 +416 370 +752 840 +41 115 +806 875 +947 912 +163 85 +958 969 +734 714 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 diff --git a/scripts/Knapsack/Data/knapPI_2_200_1000_1 b/scripts/Knapsack/Data/knapPI_2_200_1000_1 new file mode 100644 index 0000000..6d163d1 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_2_200_1000_1 @@ -0,0 +1,202 @@ +200 1008 +482 485 +257 326 +286 248 +517 421 +404 322 +713 795 +45 43 +924 845 +873 955 +160 252 +1 9 +838 901 +40 122 +58 94 +676 738 +627 574 +766 715 +862 882 +405 367 +923 984 +379 299 +461 433 +612 682 +133 72 +813 874 +97 138 +908 856 +165 145 +996 995 +623 529 +220 199 +298 277 +157 97 +723 719 +144 242 +48 107 +129 122 +148 70 +35 98 +644 600 +632 645 +272 267 +1040 972 +977 895 +312 213 +778 748 +567 487 +965 923 +1 29 +616 674 +569 540 +628 554 +493 467 +76 46 +733 710 +575 553 +288 191 +775 724 +723 730 +912 988 +64 90 +354 340 +565 549 +210 196 +922 865 +775 678 +566 570 +934 936 +626 722 +742 651 +194 123 +485 431 +483 508 +617 585 +876 853 +653 642 +896 992 +652 725 +220 286 +727 812 +900 859 +563 663 +56 88 +157 179 +280 187 +537 619 +284 261 +920 846 +124 192 +239 261 +459 514 +931 886 +504 530 +910 849 +382 294 +795 799 +485 391 +351 330 +289 298 +865 790 +250 275 +738 826 +75 72 +788 866 +947 951 +651 748 +595 685 +993 956 +663 564 +265 183 +338 400 +637 721 +206 207 +328 323 +618 611 +64 116 +139 109 +806 795 +412 343 +912 862 +715 685 +1 10 +929 881 +1025 984 +410 403 +273 360 +507 449 +450 541 +174 272 +882 877 +427 359 +787 707 +355 308 +734 770 +1 30 +248 208 +397 311 +159 100 +874 939 +449 422 +857 785 +286 370 +976 989 +908 969 +103 143 +1071 972 +1 28 +117 61 +697 638 +424 348 +439 347 +74 66 +442 391 +568 638 +195 295 +854 826 +281 196 +433 449 +845 855 +224 143 +487 487 +181 140 +496 564 +690 615 +124 135 +575 564 +374 360 +766 793 +149 163 +776 859 +793 760 +674 711 +696 662 +90 159 +732 660 +214 268 +935 948 +228 315 +619 676 +349 341 +734 689 +964 894 +644 706 +484 490 +491 478 +628 671 +1009 932 +944 899 +315 237 +92 187 +554 472 +757 772 +88 98 +952 906 +818 911 +628 635 +316 225 +818 823 +255 164 +432 343 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 diff --git a/scripts/Knapsack/Data/knapPI_2_500_1000_1 b/scripts/Knapsack/Data/knapPI_2_500_1000_1 new file mode 100644 index 0000000..10207e4 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_2_500_1000_1 @@ -0,0 +1,502 @@ +500 2543 +482 485 +257 326 +286 248 +517 421 +404 322 +713 795 +45 43 +924 845 +873 955 +160 252 +1 9 +838 901 +40 122 +58 94 +676 738 +627 574 +766 715 +862 882 +405 367 +923 984 +379 299 +461 433 +612 682 +133 72 +813 874 +97 138 +908 856 +165 145 +996 995 +623 529 +220 199 +298 277 +157 97 +723 719 +144 242 +48 107 +129 122 +148 70 +35 98 +644 600 +632 645 +272 267 +1040 972 +977 895 +312 213 +778 748 +567 487 +965 923 +1 29 +616 674 +569 540 +628 554 +493 467 +76 46 +733 710 +575 553 +288 191 +775 724 +723 730 +912 988 +64 90 +354 340 +565 549 +210 196 +922 865 +775 678 +566 570 +934 936 +626 722 +742 651 +194 123 +485 431 +483 508 +617 585 +876 853 +653 642 +896 992 +652 725 +220 286 +727 812 +900 859 +563 663 +56 88 +157 179 +280 187 +537 619 +284 261 +920 846 +124 192 +239 261 +459 514 +931 886 +504 530 +910 849 +382 294 +795 799 +485 391 +351 330 +289 298 +865 790 +250 275 +738 826 +75 72 +788 866 +947 951 +651 748 +595 685 +993 956 +663 564 +265 183 +338 400 +637 721 +206 207 +328 323 +618 611 +64 116 +139 109 +806 795 +412 343 +912 862 +715 685 +1 10 +929 881 +1025 984 +410 403 +273 360 +507 449 +450 541 +174 272 +882 877 +427 359 +787 707 +355 308 +734 770 +1 30 +248 208 +397 311 +159 100 +874 939 +449 422 +857 785 +286 370 +976 989 +908 969 +103 143 +1071 972 +1 28 +117 61 +697 638 +424 348 +439 347 +74 66 +442 391 +568 638 +195 295 +854 826 +281 196 +433 449 +845 855 +224 143 +487 487 +181 140 +496 564 +690 615 +124 135 +575 564 +374 360 +766 793 +149 163 +776 859 +793 760 +674 711 +696 662 +90 159 +732 660 +214 268 +935 948 +228 315 +619 676 +349 341 +734 689 +964 894 +644 706 +484 490 +491 478 +628 671 +1009 932 +944 899 +315 237 +92 187 +554 472 +757 772 +88 98 +952 906 +818 911 +628 635 +316 225 +818 823 +255 164 +432 343 +763 732 +490 502 +721 740 +587 576 +530 612 +992 902 +491 454 +343 411 +880 973 +645 703 +761 850 +152 77 +241 220 +727 802 +352 403 +246 181 +1 10 +479 525 +958 919 +749 668 +551 527 +538 462 +319 291 +580 605 +501 457 +487 405 +349 417 +252 279 +731 685 +637 596 +339 307 +257 224 +271 322 +740 840 +1002 975 +404 401 +190 91 +254 327 +277 330 +100 182 +648 603 +810 793 +535 615 +702 733 +855 864 +76 16 +773 863 +917 987 +279 306 +123 34 +922 840 +613 700 +658 706 +705 787 +101 105 +807 834 +883 798 +358 310 +634 609 +786 690 +618 561 +644 579 +141 60 +466 388 +340 309 +495 407 +283 200 +352 313 +886 970 +95 33 +291 273 +217 277 +1007 997 +1 40 +219 227 +764 860 +1025 940 +600 608 +895 990 +690 590 +738 806 +1 52 +772 801 +727 764 +774 710 +340 386 +503 593 +1 50 +432 494 +228 156 +993 936 +1058 965 +130 86 +821 723 +189 184 +943 868 +343 340 +404 412 +560 487 +196 209 +418 346 +782 860 +314 307 +59 95 +778 821 +979 941 +828 821 +584 587 +122 201 +741 665 +566 527 +760 812 +385 424 +395 459 +250 343 +789 836 +492 506 +261 179 +914 916 +380 430 +537 596 +731 808 +361 269 +473 512 +737 811 +708 685 +635 567 +804 776 +827 855 +695 718 +756 853 +57 97 +178 146 +688 746 +1 15 +871 965 +415 512 +510 480 +1057 958 +764 665 +193 191 +905 964 +583 515 +696 606 +887 822 +444 536 +741 693 +12 19 +313 335 +81 101 +828 922 +354 294 +981 910 +499 410 +283 250 +545 546 +635 729 +540 609 +689 720 +946 976 +730 759 +703 798 +14 74 +644 648 +241 299 +793 785 +912 846 +461 390 +801 897 +424 416 +744 837 +272 247 +338 293 +193 144 +987 938 +432 467 +505 480 +944 955 +653 665 +38 26 +468 564 +461 449 +1 26 +576 521 +329 301 +274 321 +701 613 +432 388 +851 879 +915 990 +137 188 +927 963 +903 820 +373 300 +770 822 +160 255 +285 277 +231 153 +366 400 +317 227 +423 518 +420 447 +216 315 +772 813 +271 324 +566 502 +243 299 +725 780 +390 376 +491 516 +225 212 +392 329 +781 810 +434 486 +535 485 +368 416 +938 952 +946 894 +353 358 +1 21 +707 647 +143 44 +630 683 +364 361 +822 814 +147 231 +54 8 +91 165 +431 496 +606 699 +917 852 +553 459 +473 535 +222 314 +954 944 +369 306 +413 459 +717 637 +491 447 +447 408 +44 107 +994 962 +518 565 +448 407 +931 857 +369 317 +181 98 +815 818 +655 600 +267 288 +960 902 +611 567 +271 190 +771 749 +993 908 +359 276 +810 748 +563 592 +360 393 +264 363 +199 163 +1074 983 +131 179 +41 16 +423 478 +197 259 +779 868 +344 295 +536 596 +140 71 +669 622 +938 864 +715 644 +67 5 +321 365 +434 429 +19 64 +928 854 +759 770 +178 88 +160 157 +277 368 +467 421 +653 719 +330 271 +966 975 +817 816 +1045 962 +508 535 +492 438 +743 696 +884 881 +259 318 +56 45 +1 52 +421 496 +270 313 +99 138 +429 334 +1004 988 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_3_1000_1000_1 b/scripts/Knapsack/Data/knapPI_3_1000_1000_1 new file mode 100644 index 0000000..936772c --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_3_1000_1000_1 @@ -0,0 +1,1002 @@ +1000 4990 +585 485 +194 94 +426 326 +606 506 +348 248 +516 416 +521 421 +1092 992 +422 322 +749 649 +895 795 +337 237 +143 43 +557 457 +945 845 +915 815 +1055 955 +546 446 +352 252 +522 422 +109 9 +891 791 +1001 901 +459 359 +222 122 +767 667 +194 94 +698 598 +838 738 +107 7 +674 574 +644 544 +815 715 +434 334 +982 882 +866 766 +467 367 +1094 994 +1084 984 +993 893 +399 299 +733 633 +533 433 +231 131 +782 682 +528 428 +172 72 +800 700 +974 874 +717 617 +238 138 +974 874 +956 856 +820 720 +245 145 +519 419 +1095 995 +894 794 +629 529 +296 196 +299 199 +1097 997 +377 277 +216 116 +197 97 +1008 908 +819 719 +639 539 +342 242 +807 707 +207 107 +669 569 +222 122 +637 537 +170 70 +1031 931 +198 98 +826 726 +700 600 +587 487 +745 645 +872 772 +367 267 +613 513 +1072 972 +181 81 +995 895 +1043 943 +313 213 +158 58 +848 748 +403 303 +587 487 +864 764 +1023 923 +636 536 +129 29 +824 724 +774 674 +889 789 +640 540 +579 479 +654 554 +242 142 +567 467 +439 339 +146 46 +741 641 +810 710 +296 196 +653 553 +594 494 +291 191 +166 66 +824 724 +924 824 +830 730 +308 208 +1088 988 +811 711 +190 90 +900 800 +440 340 +414 314 +649 549 +389 289 +296 196 +501 401 +965 865 +566 466 +778 678 +789 689 +670 570 +933 833 +1036 936 +325 225 +822 722 +344 244 +751 651 +949 849 +223 123 +213 113 +531 431 +479 379 +608 508 +461 361 +685 585 +165 65 +953 853 +586 486 +742 642 +786 686 +1092 992 +386 286 +825 725 +989 889 +386 286 +124 24 +912 812 +591 491 +959 859 +991 891 +763 663 +190 90 +188 88 +281 181 +279 179 +314 214 +287 187 +117 17 +719 619 +572 472 +361 261 +518 418 +946 846 +519 419 +292 192 +456 356 +361 261 +782 682 +614 514 +406 306 +986 886 +301 201 +630 530 +485 385 +949 849 +1052 952 +394 294 +600 500 +899 799 +294 194 +491 391 +837 737 +430 330 +424 324 +398 298 +1092 992 +890 790 +324 224 +375 275 +360 260 +926 826 +197 97 +172 72 +310 210 +966 866 +749 649 +1051 951 +1019 919 +848 748 +163 63 +785 685 +1058 958 +1056 956 +904 804 +664 564 +618 518 +283 183 +528 428 +500 400 +637 537 +821 721 +446 346 +307 207 +253 153 +423 323 +1071 971 +711 611 +762 662 +216 116 +297 197 +209 109 +191 91 +895 795 +629 529 +443 343 +226 126 +962 862 +847 747 +785 685 +569 469 +110 10 +870 770 +981 881 +1034 934 +1084 984 +823 723 +503 403 +995 895 +460 360 +668 568 +549 449 +272 172 +641 541 +1058 958 +372 272 +483 383 +977 877 +408 308 +459 359 +1070 970 +807 707 +683 583 +408 308 +148 48 +870 770 +1030 930 +130 30 +669 569 +308 208 +103 3 +411 311 +120 20 +200 100 +709 609 +1039 939 +987 887 +522 422 +925 825 +885 785 +1030 930 +470 370 +1004 904 +1089 989 +341 241 +1069 969 +479 379 +243 143 +476 376 +1072 972 +1062 962 +128 28 +989 889 +161 61 +543 443 +738 638 +316 216 +448 348 +438 338 +447 347 +260 160 +166 66 +506 406 +491 391 +259 159 +738 638 +131 31 +395 295 +304 204 +926 826 +520 420 +296 196 +253 153 +549 449 +525 425 +955 855 +431 331 +243 143 +665 565 +587 487 +938 838 +240 140 +109 9 +664 564 +1018 918 +715 615 +633 533 +235 135 +332 232 +664 564 +1057 957 +460 360 +691 591 +893 793 +676 576 +263 163 +846 746 +959 859 +477 377 +860 760 +958 858 +811 711 +186 86 +762 662 +534 434 +259 159 +658 558 +760 660 +379 279 +368 268 +940 840 +1048 948 +835 735 +415 315 +674 574 +776 676 +226 126 +441 341 +1012 912 +789 689 +839 739 +994 894 +921 821 +806 706 +725 625 +590 490 +1017 917 +578 478 +301 201 +771 671 +1093 993 +1032 932 +249 149 +999 899 +152 52 +337 237 +859 759 +287 187 +367 267 +572 472 +356 256 +872 772 +883 783 +198 98 +217 117 +1006 906 +616 516 +1011 911 +280 180 +735 635 +125 25 +325 225 +480 380 +923 823 +812 712 +264 164 +366 266 +443 343 +316 216 +832 732 +548 448 +602 502 +641 541 +840 740 +764 664 +676 576 +1054 954 +712 612 +826 726 +1002 902 +872 772 +554 454 +631 531 +511 411 +1043 943 +1073 973 +850 750 +803 703 +427 327 +950 850 +1017 917 +177 77 +105 5 +320 220 +213 113 +902 802 +1013 913 +503 403 +891 791 +281 181 +1098 998 +110 10 +959 859 +625 525 +445 345 +1019 919 +531 431 +768 668 +775 675 +627 527 +933 833 +562 462 +538 438 +391 291 +623 523 +705 605 +1016 916 +557 457 +520 420 +505 405 +215 115 +517 417 +760 660 +379 279 +361 261 +785 685 +872 772 +696 596 +488 388 +407 307 +864 764 +324 224 +943 843 +422 322 +306 206 +940 840 +507 407 +1075 975 +739 639 +501 401 +952 852 +191 91 +642 542 +427 327 +160 60 +430 330 +857 757 +282 182 +182 82 +703 603 +737 637 +893 793 +193 93 +715 615 +714 614 +833 733 +236 136 +964 864 +287 187 +116 16 +202 102 +963 863 +1072 972 +1087 987 +263 163 +406 306 +601 501 +134 34 +577 477 +940 840 +592 492 +800 700 +221 121 +806 706 +180 80 +887 787 +238 138 +205 105 +760 660 +934 834 +329 229 +898 798 +927 827 +410 310 +548 448 +709 609 +330 230 +790 690 +932 832 +661 561 +589 489 +679 579 +686 586 +160 60 +391 291 +488 388 +765 665 +409 309 +760 660 +507 407 +802 702 +300 200 +253 153 +413 313 +706 606 +1070 970 +223 123 +133 33 +353 253 +373 273 +809 709 +377 277 +932 832 +1097 997 +208 108 +140 40 +988 888 +327 227 +581 481 +960 860 +383 283 +1040 940 +958 858 +708 608 +384 284 +1090 990 +811 711 +690 590 +950 850 +906 806 +339 239 +152 52 +1043 943 +901 801 +295 195 +864 764 +195 95 +810 710 +510 410 +486 386 +764 664 +693 593 +1000 900 +150 50 +212 112 +594 494 +1063 963 +256 156 +854 754 +1036 936 +558 458 +1065 965 +119 19 +186 86 +325 225 +823 723 +669 569 +284 184 +197 97 +968 868 +294 194 +440 340 +854 754 +512 412 +702 602 +587 487 +161 61 +309 209 +795 695 +446 346 +447 347 +960 860 +819 719 +407 307 +200 100 +195 95 +197 97 +921 821 +943 843 +1041 941 +845 745 +921 821 +386 286 +687 587 +592 492 +301 201 +216 116 +765 665 +631 531 +627 527 +524 424 +912 812 +353 253 +524 424 +526 426 +559 459 +513 413 +443 343 +1080 980 +936 836 +391 291 +606 506 +933 833 +279 179 +586 486 +1016 916 +109 9 +530 430 +675 575 +696 596 +1022 922 +908 808 +245 145 +369 269 +997 897 +612 512 +504 404 +911 811 +842 742 +785 685 +828 728 +667 567 +369 269 +876 776 +203 103 +955 855 +845 745 +818 718 +135 35 +953 853 +879 779 +197 97 +171 71 +246 146 +180 80 +846 746 +942 842 +115 15 +228 128 +1065 965 +1041 941 +612 512 +327 227 +580 480 +130 30 +1058 958 +442 342 +765 665 +705 605 +291 191 +631 531 +1064 964 +464 364 +615 515 +459 359 +706 606 +967 867 +922 822 +920 820 +636 536 +413 313 +793 693 +307 207 +119 19 +1011 911 +435 335 +408 308 +201 101 +530 430 +1022 922 +785 685 +394 294 +741 641 +1010 910 +213 113 +510 410 +241 141 +350 250 +790 690 +646 546 +800 700 +829 729 +659 559 +709 609 +581 481 +820 720 +603 503 +1076 976 +866 766 +859 759 +107 7 +898 798 +982 882 +174 74 +959 859 +748 648 +282 182 +399 299 +525 425 +885 785 +642 542 +946 846 +783 683 +490 390 +953 853 +997 897 +1038 938 +516 416 +189 89 +937 837 +724 624 +347 247 +281 181 +393 293 +978 878 +244 144 +1033 933 +1038 938 +680 580 +567 467 +352 252 +580 480 +307 207 +1055 955 +758 658 +765 665 +120 20 +126 26 +1054 954 +664 564 +447 347 +549 449 +859 759 +126 26 +546 446 +621 521 +114 14 +401 301 +757 657 +421 321 +810 710 +713 613 +1080 980 +488 388 +288 188 +979 879 +736 636 +1090 990 +303 203 +288 188 +532 432 +1063 963 +229 129 +920 820 +730 630 +400 300 +609 509 +922 822 +337 237 +355 255 +473 373 +377 277 +938 838 +253 153 +495 395 +500 400 +792 692 +327 227 +203 103 +618 518 +318 218 +547 447 +484 384 +415 315 +1031 931 +913 813 +496 396 +424 324 +489 389 +602 502 +740 640 +399 299 +387 287 +880 780 +397 297 +476 376 +1077 977 +616 516 +612 512 +312 212 +319 219 +429 329 +655 555 +910 810 +498 398 +586 486 +389 289 +585 485 +898 798 +516 416 +698 598 +1052 952 +149 49 +994 894 +672 572 +458 358 +797 697 +121 21 +870 770 +747 647 +825 725 +144 44 +642 542 +783 683 +314 214 +461 361 +987 887 +914 814 +145 45 +331 231 +194 94 +108 8 +382 282 +265 165 +182 82 +596 496 +419 319 +799 699 +726 626 +952 852 +246 146 +559 459 +641 541 +635 535 +974 874 +414 314 +825 725 +1044 944 +877 777 +406 306 +654 554 +559 459 +308 208 +737 637 +887 787 +547 447 +1076 976 +508 408 +1012 912 +207 107 +544 444 +1062 962 +103 3 +665 565 +401 301 +507 407 +264 164 +957 857 +537 437 +417 317 +752 652 +198 98 +864 764 +918 818 +141 41 +700 600 +837 737 +388 288 +276 176 +1002 902 +236 136 +667 567 +228 128 +290 190 +494 394 +849 749 +335 235 +1008 908 +142 42 +376 276 +924 824 +848 748 +784 684 +692 592 +1079 979 +493 393 +668 568 +463 363 +467 367 +263 163 +152 52 +1083 983 +742 642 +279 179 +435 335 +116 16 +226 126 +578 478 +230 130 +359 259 +683 583 +968 868 +229 129 +395 295 +852 752 +696 596 +267 167 +171 71 +956 856 +722 622 +740 640 +964 864 +870 770 +744 644 +531 431 +105 5 +295 195 +465 365 +548 448 +529 429 +801 701 +164 64 +1052 952 +954 854 +980 880 +870 770 +268 168 +188 88 +179 79 +257 157 +1061 961 +468 368 +572 472 +521 421 +317 217 +819 719 +809 709 +371 271 +247 147 +1075 975 +396 296 +916 816 +1009 909 +1062 962 +864 764 +635 535 +351 251 +538 438 +978 878 +796 696 +853 753 +981 881 +670 570 +418 318 +353 253 +145 45 +766 666 +152 52 +1031 931 +596 496 +533 433 +413 313 +910 810 +238 138 +778 678 +434 334 +223 123 +1088 988 +312 212 +0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_3_100_1000_1 b/scripts/Knapsack/Data/knapPI_3_100_1000_1 new file mode 100644 index 0000000..ded5c60 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_3_100_1000_1 @@ -0,0 +1,102 @@ +100 997 +585 485 +194 94 +426 326 +606 506 +348 248 +516 416 +521 421 +1092 992 +422 322 +749 649 +895 795 +337 237 +143 43 +557 457 +945 845 +915 815 +1055 955 +546 446 +352 252 +522 422 +109 9 +891 791 +1001 901 +459 359 +222 122 +767 667 +194 94 +698 598 +838 738 +107 7 +674 574 +644 544 +815 715 +434 334 +982 882 +866 766 +467 367 +1094 994 +1084 984 +993 893 +399 299 +733 633 +533 433 +231 131 +782 682 +528 428 +172 72 +800 700 +974 874 +717 617 +238 138 +974 874 +956 856 +820 720 +245 145 +519 419 +1095 995 +894 794 +629 529 +296 196 +299 199 +1097 997 +377 277 +216 116 +197 97 +1008 908 +819 719 +639 539 +342 242 +807 707 +207 107 +669 569 +222 122 +637 537 +170 70 +1031 931 +198 98 +826 726 +700 600 +587 487 +745 645 +872 772 +367 267 +613 513 +1072 972 +181 81 +995 895 +1043 943 +313 213 +158 58 +848 748 +403 303 +587 487 +864 764 +1023 923 +636 536 +129 29 +824 724 +774 674 +889 789 +0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_3_2000_1000_1 b/scripts/Knapsack/Data/knapPI_3_2000_1000_1 new file mode 100644 index 0000000..444b1e8 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_3_2000_1000_1 @@ -0,0 +1,2002 @@ +2000 9819 +585 485 +194 94 +426 326 +606 506 +348 248 +516 416 +521 421 +1092 992 +422 322 +749 649 +895 795 +337 237 +143 43 +557 457 +945 845 +915 815 +1055 955 +546 446 +352 252 +522 422 +109 9 +891 791 +1001 901 +459 359 +222 122 +767 667 +194 94 +698 598 +838 738 +107 7 +674 574 +644 544 +815 715 +434 334 +982 882 +866 766 +467 367 +1094 994 +1084 984 +993 893 +399 299 +733 633 +533 433 +231 131 +782 682 +528 428 +172 72 +800 700 +974 874 +717 617 +238 138 +974 874 +956 856 +820 720 +245 145 +519 419 +1095 995 +894 794 +629 529 +296 196 +299 199 +1097 997 +377 277 +216 116 +197 97 +1008 908 +819 719 +639 539 +342 242 +807 707 +207 107 +669 569 +222 122 +637 537 +170 70 +1031 931 +198 98 +826 726 +700 600 +587 487 +745 645 +872 772 +367 267 +613 513 +1072 972 +181 81 +995 895 +1043 943 +313 213 +158 58 +848 748 +403 303 +587 487 +864 764 +1023 923 +636 536 +129 29 +824 724 +774 674 +889 789 +640 540 +579 479 +654 554 +242 142 +567 467 +439 339 +146 46 +741 641 +810 710 +296 196 +653 553 +594 494 +291 191 +166 66 +824 724 +924 824 +830 730 +308 208 +1088 988 +811 711 +190 90 +900 800 +440 340 +414 314 +649 549 +389 289 +296 196 +501 401 +965 865 +566 466 +778 678 +789 689 +670 570 +933 833 +1036 936 +325 225 +822 722 +344 244 +751 651 +949 849 +223 123 +213 113 +531 431 +479 379 +608 508 +461 361 +685 585 +165 65 +953 853 +586 486 +742 642 +786 686 +1092 992 +386 286 +825 725 +989 889 +386 286 +124 24 +912 812 +591 491 +959 859 +991 891 +763 663 +190 90 +188 88 +281 181 +279 179 +314 214 +287 187 +117 17 +719 619 +572 472 +361 261 +518 418 +946 846 +519 419 +292 192 +456 356 +361 261 +782 682 +614 514 +406 306 +986 886 +301 201 +630 530 +485 385 +949 849 +1052 952 +394 294 +600 500 +899 799 +294 194 +491 391 +837 737 +430 330 +424 324 +398 298 +1092 992 +890 790 +324 224 +375 275 +360 260 +926 826 +197 97 +172 72 +310 210 +966 866 +749 649 +1051 951 +1019 919 +848 748 +163 63 +785 685 +1058 958 +1056 956 +904 804 +664 564 +618 518 +283 183 +528 428 +500 400 +637 537 +821 721 +446 346 +307 207 +253 153 +423 323 +1071 971 +711 611 +762 662 +216 116 +297 197 +209 109 +191 91 +895 795 +629 529 +443 343 +226 126 +962 862 +847 747 +785 685 +569 469 +110 10 +870 770 +981 881 +1034 934 +1084 984 +823 723 +503 403 +995 895 +460 360 +668 568 +549 449 +272 172 +641 541 +1058 958 +372 272 +483 383 +977 877 +408 308 +459 359 +1070 970 +807 707 +683 583 +408 308 +148 48 +870 770 +1030 930 +130 30 +669 569 +308 208 +103 3 +411 311 +120 20 +200 100 +709 609 +1039 939 +987 887 +522 422 +925 825 +885 785 +1030 930 +470 370 +1004 904 +1089 989 +341 241 +1069 969 +479 379 +243 143 +476 376 +1072 972 +1062 962 +128 28 +989 889 +161 61 +543 443 +738 638 +316 216 +448 348 +438 338 +447 347 +260 160 +166 66 +506 406 +491 391 +259 159 +738 638 +131 31 +395 295 +304 204 +926 826 +520 420 +296 196 +253 153 +549 449 +525 425 +955 855 +431 331 +243 143 +665 565 +587 487 +938 838 +240 140 +109 9 +664 564 +1018 918 +715 615 +633 533 +235 135 +332 232 +664 564 +1057 957 +460 360 +691 591 +893 793 +676 576 +263 163 +846 746 +959 859 +477 377 +860 760 +958 858 +811 711 +186 86 +762 662 +534 434 +259 159 +658 558 +760 660 +379 279 +368 268 +940 840 +1048 948 +835 735 +415 315 +674 574 +776 676 +226 126 +441 341 +1012 912 +789 689 +839 739 +994 894 +921 821 +806 706 +725 625 +590 490 +1017 917 +578 478 +301 201 +771 671 +1093 993 +1032 932 +249 149 +999 899 +152 52 +337 237 +859 759 +287 187 +367 267 +572 472 +356 256 +872 772 +883 783 +198 98 +217 117 +1006 906 +616 516 +1011 911 +280 180 +735 635 +125 25 +325 225 +480 380 +923 823 +812 712 +264 164 +366 266 +443 343 +316 216 +832 732 +548 448 +602 502 +641 541 +840 740 +764 664 +676 576 +1054 954 +712 612 +826 726 +1002 902 +872 772 +554 454 +631 531 +511 411 +1043 943 +1073 973 +850 750 +803 703 +427 327 +950 850 +1017 917 +177 77 +105 5 +320 220 +213 113 +902 802 +1013 913 +503 403 +891 791 +281 181 +1098 998 +110 10 +959 859 +625 525 +445 345 +1019 919 +531 431 +768 668 +775 675 +627 527 +933 833 +562 462 +538 438 +391 291 +623 523 +705 605 +1016 916 +557 457 +520 420 +505 405 +215 115 +517 417 +760 660 +379 279 +361 261 +785 685 +872 772 +696 596 +488 388 +407 307 +864 764 +324 224 +943 843 +422 322 +306 206 +940 840 +507 407 +1075 975 +739 639 +501 401 +952 852 +191 91 +642 542 +427 327 +160 60 +430 330 +857 757 +282 182 +182 82 +703 603 +737 637 +893 793 +193 93 +715 615 +714 614 +833 733 +236 136 +964 864 +287 187 +116 16 +202 102 +963 863 +1072 972 +1087 987 +263 163 +406 306 +601 501 +134 34 +577 477 +940 840 +592 492 +800 700 +221 121 +806 706 +180 80 +887 787 +238 138 +205 105 +760 660 +934 834 +329 229 +898 798 +927 827 +410 310 +548 448 +709 609 +330 230 +790 690 +932 832 +661 561 +589 489 +679 579 +686 586 +160 60 +391 291 +488 388 +765 665 +409 309 +760 660 +507 407 +802 702 +300 200 +253 153 +413 313 +706 606 +1070 970 +223 123 +133 33 +353 253 +373 273 +809 709 +377 277 +932 832 +1097 997 +208 108 +140 40 +988 888 +327 227 +581 481 +960 860 +383 283 +1040 940 +958 858 +708 608 +384 284 +1090 990 +811 711 +690 590 +950 850 +906 806 +339 239 +152 52 +1043 943 +901 801 +295 195 +864 764 +195 95 +810 710 +510 410 +486 386 +764 664 +693 593 +1000 900 +150 50 +212 112 +594 494 +1063 963 +256 156 +854 754 +1036 936 +558 458 +1065 965 +119 19 +186 86 +325 225 +823 723 +669 569 +284 184 +197 97 +968 868 +294 194 +440 340 +854 754 +512 412 +702 602 +587 487 +161 61 +309 209 +795 695 +446 346 +447 347 +960 860 +819 719 +407 307 +200 100 +195 95 +197 97 +921 821 +943 843 +1041 941 +845 745 +921 821 +386 286 +687 587 +592 492 +301 201 +216 116 +765 665 +631 531 +627 527 +524 424 +912 812 +353 253 +524 424 +526 426 +559 459 +513 413 +443 343 +1080 980 +936 836 +391 291 +606 506 +933 833 +279 179 +586 486 +1016 916 +109 9 +530 430 +675 575 +696 596 +1022 922 +908 808 +245 145 +369 269 +997 897 +612 512 +504 404 +911 811 +842 742 +785 685 +828 728 +667 567 +369 269 +876 776 +203 103 +955 855 +845 745 +818 718 +135 35 +953 853 +879 779 +197 97 +171 71 +246 146 +180 80 +846 746 +942 842 +115 15 +228 128 +1065 965 +1041 941 +612 512 +327 227 +580 480 +130 30 +1058 958 +442 342 +765 665 +705 605 +291 191 +631 531 +1064 964 +464 364 +615 515 +459 359 +706 606 +967 867 +922 822 +920 820 +636 536 +413 313 +793 693 +307 207 +119 19 +1011 911 +435 335 +408 308 +201 101 +530 430 +1022 922 +785 685 +394 294 +741 641 +1010 910 +213 113 +510 410 +241 141 +350 250 +790 690 +646 546 +800 700 +829 729 +659 559 +709 609 +581 481 +820 720 +603 503 +1076 976 +866 766 +859 759 +107 7 +898 798 +982 882 +174 74 +959 859 +748 648 +282 182 +399 299 +525 425 +885 785 +642 542 +946 846 +783 683 +490 390 +953 853 +997 897 +1038 938 +516 416 +189 89 +937 837 +724 624 +347 247 +281 181 +393 293 +978 878 +244 144 +1033 933 +1038 938 +680 580 +567 467 +352 252 +580 480 +307 207 +1055 955 +758 658 +765 665 +120 20 +126 26 +1054 954 +664 564 +447 347 +549 449 +859 759 +126 26 +546 446 +621 521 +114 14 +401 301 +757 657 +421 321 +810 710 +713 613 +1080 980 +488 388 +288 188 +979 879 +736 636 +1090 990 +303 203 +288 188 +532 432 +1063 963 +229 129 +920 820 +730 630 +400 300 +609 509 +922 822 +337 237 +355 255 +473 373 +377 277 +938 838 +253 153 +495 395 +500 400 +792 692 +327 227 +203 103 +618 518 +318 218 +547 447 +484 384 +415 315 +1031 931 +913 813 +496 396 +424 324 +489 389 +602 502 +740 640 +399 299 +387 287 +880 780 +397 297 +476 376 +1077 977 +616 516 +612 512 +312 212 +319 219 +429 329 +655 555 +910 810 +498 398 +586 486 +389 289 +585 485 +898 798 +516 416 +698 598 +1052 952 +149 49 +994 894 +672 572 +458 358 +797 697 +121 21 +870 770 +747 647 +825 725 +144 44 +642 542 +783 683 +314 214 +461 361 +987 887 +914 814 +145 45 +331 231 +194 94 +108 8 +382 282 +265 165 +182 82 +596 496 +419 319 +799 699 +726 626 +952 852 +246 146 +559 459 +641 541 +635 535 +974 874 +414 314 +825 725 +1044 944 +877 777 +406 306 +654 554 +559 459 +308 208 +737 637 +887 787 +547 447 +1076 976 +508 408 +1012 912 +207 107 +544 444 +1062 962 +103 3 +665 565 +401 301 +507 407 +264 164 +957 857 +537 437 +417 317 +752 652 +198 98 +864 764 +918 818 +141 41 +700 600 +837 737 +388 288 +276 176 +1002 902 +236 136 +667 567 +228 128 +290 190 +494 394 +849 749 +335 235 +1008 908 +142 42 +376 276 +924 824 +848 748 +784 684 +692 592 +1079 979 +493 393 +668 568 +463 363 +467 367 +263 163 +152 52 +1083 983 +742 642 +279 179 +435 335 +116 16 +226 126 +578 478 +230 130 +359 259 +683 583 +968 868 +229 129 +395 295 +852 752 +696 596 +267 167 +171 71 +956 856 +722 622 +740 640 +964 864 +870 770 +744 644 +531 431 +105 5 +295 195 +465 365 +548 448 +529 429 +801 701 +164 64 +1052 952 +954 854 +980 880 +870 770 +268 168 +188 88 +179 79 +257 157 +1061 961 +468 368 +572 472 +521 421 +317 217 +819 719 +809 709 +371 271 +247 147 +1075 975 +396 296 +916 816 +1009 909 +1062 962 +864 764 +635 535 +351 251 +538 438 +978 878 +796 696 +853 753 +981 881 +670 570 +418 318 +353 253 +145 45 +766 666 +152 52 +1031 931 +596 496 +533 433 +413 313 +910 810 +238 138 +778 678 +434 334 +223 123 +1088 988 +312 212 +608 508 +166 66 +870 770 +306 206 +851 751 +850 750 +880 780 +164 64 +541 441 +566 466 +307 207 +437 337 +616 516 +610 510 +774 674 +896 796 +508 408 +275 175 +1020 920 +537 437 +673 573 +1038 938 +734 634 +948 848 +978 878 +661 561 +1090 990 +818 718 +926 826 +1048 948 +796 696 +749 649 +900 800 +669 569 +511 411 +763 663 +522 422 +682 582 +807 707 +943 843 +434 334 +302 202 +1086 986 +802 702 +594 494 +679 579 +250 150 +825 725 +662 562 +903 803 +480 380 +440 340 +932 832 +256 156 +1079 979 +932 832 +476 376 +702 602 +611 511 +334 234 +514 414 +788 688 +260 160 +284 184 +1082 982 +1078 978 +338 238 +513 413 +590 490 +733 633 +999 899 +685 585 +351 251 +706 606 +626 526 +1063 963 +997 897 +450 350 +139 39 +342 242 +757 657 +639 539 +552 452 +839 739 +638 538 +367 267 +931 831 +265 165 +560 460 +277 177 +285 185 +820 720 +1034 934 +902 802 +540 440 +744 644 +590 490 +182 82 +268 168 +898 798 +171 71 +297 197 +1077 977 +273 173 +558 458 +181 81 +304 204 +335 235 +903 803 +212 112 +239 139 +203 103 +499 399 +368 268 +520 420 +979 879 +1091 991 +743 643 +678 578 +206 106 +1072 972 +222 122 +277 177 +544 444 +498 398 +362 262 +448 348 +791 691 +596 496 +1097 997 +376 276 +546 446 +925 825 +271 171 +714 614 +649 549 +221 121 +381 281 +830 730 +311 211 +441 341 +212 112 +384 284 +508 408 +798 698 +830 730 +117 17 +463 363 +646 546 +189 89 +772 672 +705 605 +1074 974 +1038 938 +966 866 +268 168 +477 377 +805 705 +659 559 +147 47 +440 340 +500 400 +627 527 +315 215 +879 779 +214 114 +861 761 +151 51 +583 483 +981 881 +192 92 +649 549 +490 390 +779 679 +683 583 +428 328 +761 661 +350 250 +491 391 +303 203 +436 336 +581 481 +761 661 +852 752 +225 125 +807 707 +189 89 +182 82 +375 275 +163 63 +459 359 +760 660 +278 178 +121 21 +880 780 +387 287 +142 42 +319 219 +105 5 +600 500 +480 380 +920 820 +872 772 +195 95 +916 816 +144 44 +109 9 +848 748 +584 484 +778 678 +645 545 +376 276 +689 589 +578 478 +257 157 +763 663 +1001 901 +694 594 +877 777 +857 757 +174 74 +1047 947 +347 247 +548 448 +155 55 +670 570 +579 479 +413 313 +885 785 +1081 981 +1058 958 +895 795 +780 680 +652 552 +493 393 +489 389 +1044 944 +380 280 +696 596 +964 864 +719 619 +736 636 +711 611 +612 512 +952 852 +992 892 +383 283 +284 184 +399 299 +1047 947 +866 766 +714 614 +412 312 +725 625 +926 826 +249 149 +826 726 +477 377 +833 733 +574 474 +905 805 +118 18 +779 679 +762 662 +503 403 +516 416 +1064 964 +101 1 +437 337 +630 530 +641 541 +852 752 +578 478 +122 22 +469 369 +1081 981 +1046 946 +877 777 +921 821 +1057 957 +933 833 +375 275 +937 837 +684 584 +590 490 +682 582 +137 37 +221 121 +694 594 +1051 951 +229 129 +768 668 +358 258 +218 118 +346 246 +419 319 +462 362 +996 896 +855 755 +621 521 +604 504 +1048 948 +171 71 +348 248 +277 177 +574 474 +276 176 +451 351 +903 803 +154 54 +337 237 +255 155 +777 677 +760 660 +133 33 +971 871 +215 115 +586 486 +697 597 +394 294 +869 769 +525 425 +636 536 +345 245 +1056 956 +482 382 +441 341 +471 371 +284 184 +808 708 +334 234 +644 544 +669 569 +894 794 +316 216 +487 387 +637 537 +838 738 +184 84 +620 520 +910 810 +381 281 +757 657 +602 502 +133 33 +191 91 +259 159 +603 503 +620 520 +1024 924 +768 668 +116 16 +387 287 +133 33 +329 229 +444 344 +474 374 +449 349 +574 474 +706 606 +772 672 +996 896 +1015 915 +695 595 +611 511 +541 441 +223 123 +202 102 +669 569 +152 52 +299 199 +754 654 +496 396 +810 710 +815 715 +534 434 +159 59 +345 245 +710 610 +136 36 +1017 917 +761 661 +1027 927 +513 413 +370 270 +113 13 +217 117 +470 370 +616 516 +500 400 +315 215 +295 195 +316 216 +1084 984 +337 237 +576 476 +715 615 +264 164 +599 499 +505 405 +577 477 +774 674 +860 760 +296 196 +385 285 +708 608 +156 56 +1007 907 +1066 966 +632 532 +722 622 +151 51 +321 221 +816 716 +294 194 +427 327 +191 91 +980 880 +447 347 +810 710 +352 252 +367 267 +573 473 +500 400 +616 516 +476 376 +485 385 +709 609 +457 357 +420 320 +1058 958 +296 196 +765 665 +638 538 +892 792 +1035 935 +164 64 +504 404 +520 420 +200 100 +771 671 +226 126 +1068 968 +955 855 +977 877 +194 94 +277 177 +831 731 +623 523 +353 253 +239 139 +108 8 +252 152 +493 393 +832 732 +643 543 +346 246 +448 348 +665 565 +418 318 +840 740 +589 489 +1002 902 +122 22 +117 17 +1098 998 +1073 973 +149 49 +398 298 +481 381 +711 611 +110 10 +132 32 +529 429 +111 11 +321 221 +437 337 +250 150 +236 136 +817 717 +989 889 +630 530 +622 522 +432 332 +905 805 +1042 942 +128 28 +665 565 +1031 931 +316 216 +857 757 +161 61 +709 609 +270 170 +644 544 +972 872 +1005 905 +744 644 +695 595 +308 208 +346 246 +780 680 +213 113 +797 697 +275 175 +739 639 +256 156 +779 679 +344 244 +1061 961 +983 883 +461 361 +365 265 +902 802 +983 883 +459 359 +562 462 +939 839 +585 485 +818 718 +372 272 +380 280 +304 204 +352 252 +1084 984 +380 280 +509 409 +202 102 +498 398 +715 615 +1009 909 +396 296 +470 370 +581 481 +982 882 +1056 956 +314 214 +330 230 +866 766 +359 259 +135 35 +1022 922 +521 421 +806 706 +371 271 +372 272 +470 370 +256 156 +948 848 +652 552 +150 50 +585 485 +1076 976 +636 536 +370 270 +170 70 +896 796 +1002 902 +1063 963 +552 452 +479 379 +135 35 +1091 991 +1047 947 +651 551 +478 378 +997 897 +157 57 +407 307 +452 352 +521 421 +769 669 +174 74 +802 702 +488 388 +241 141 +659 559 +558 458 +1080 980 +563 463 +715 615 +856 756 +781 681 +987 887 +331 231 +432 332 +307 207 +628 528 +918 818 +756 656 +431 331 +354 254 +1079 979 +887 787 +545 445 +595 495 +448 348 +470 370 +824 724 +110 10 +501 401 +300 200 +746 646 +427 327 +768 668 +117 17 +342 242 +474 374 +402 302 +855 755 +961 861 +1080 980 +930 830 +476 376 +177 77 +108 8 +541 441 +132 32 +689 589 +560 460 +1090 990 +904 804 +289 189 +123 23 +968 868 +969 869 +1096 996 +1043 943 +463 363 +815 715 +337 237 +728 628 +520 420 +173 73 +665 565 +299 199 +314 214 +138 38 +433 333 +309 209 +826 726 +427 327 +275 175 +1012 912 +158 58 +899 799 +725 625 +472 372 +166 66 +1076 976 +269 169 +220 120 +575 475 +767 667 +304 204 +288 188 +190 90 +128 28 +596 496 +804 704 +101 1 +749 649 +574 474 +846 746 +549 449 +797 697 +352 252 +812 712 +432 332 +389 289 +387 287 +725 625 +289 189 +1053 953 +989 889 +562 462 +163 63 +402 302 +478 378 +179 79 +306 206 +141 41 +997 897 +923 823 +330 230 +1008 908 +482 382 +765 665 +675 575 +136 36 +160 60 +832 732 +629 529 +909 809 +577 477 +166 66 +390 290 +391 291 +189 89 +691 591 +1061 961 +683 583 +561 461 +352 252 +802 702 +579 479 +632 532 +630 530 +780 680 +324 224 +153 53 +888 788 +742 642 +409 309 +1100 1000 +466 366 +991 891 +452 352 +922 822 +502 402 +252 152 +645 545 +424 324 +213 113 +733 633 +1067 967 +367 267 +554 454 +481 381 +823 723 +372 272 +114 14 +606 506 +120 20 +519 419 +408 308 +561 461 +744 644 +626 526 +813 713 +1078 978 +582 482 +568 468 +436 336 +829 729 +389 289 +895 795 +596 496 +681 581 +426 326 +483 383 +630 530 +326 226 +267 167 +521 421 +622 522 +486 386 +930 830 +373 273 +191 91 +584 484 +216 116 +776 676 +847 747 +207 107 +495 395 +329 229 +1058 958 +1002 902 +856 756 +1062 962 +362 262 +205 105 +803 703 +184 84 +611 511 +1091 991 +581 481 +801 701 +549 449 +789 689 +988 888 +755 655 +699 599 +700 600 +406 306 +638 538 +592 492 +599 499 +903 803 +981 881 +545 445 +1081 981 +416 316 +573 473 +989 889 +483 383 +885 785 +779 679 +865 765 +673 573 +591 491 +689 589 +689 589 +580 480 +224 124 +245 145 +841 741 +724 624 +998 898 +1023 923 +825 725 +1015 915 +782 682 +332 232 +231 131 +1074 974 +498 398 +835 735 +1006 906 +778 678 +853 753 +740 640 +412 312 +744 644 +890 790 +312 212 +401 301 +223 123 +1045 945 +353 253 +547 447 +1043 943 +297 197 +118 18 +127 27 +1016 916 +673 573 +427 327 +689 589 +740 640 +1034 934 +715 615 +309 209 +570 470 +629 529 +755 655 +999 899 +388 288 +115 15 +501 401 +692 592 +940 840 +192 92 +733 633 +675 575 +807 707 +914 814 +524 424 +454 354 +782 682 +227 127 +294 194 +474 374 +955 855 +666 566 +290 190 +694 594 +828 728 +1073 973 +278 178 +745 645 +375 275 +703 603 +188 88 +812 712 +467 367 +132 32 +644 544 +398 298 +838 738 +661 561 +1063 963 +1006 906 +560 460 +726 626 +366 266 +243 143 +827 727 +604 504 +133 33 +936 836 +542 442 +461 361 +728 628 +531 431 +484 384 +654 554 +344 244 +124 24 +582 482 +516 416 +865 765 +835 735 +546 446 +343 243 +347 247 +554 454 +1013 913 +1032 932 +660 560 +594 494 +628 528 +748 648 +694 594 +457 357 +1035 935 +696 596 +562 462 +888 788 +721 621 +636 536 +760 660 +859 759 +664 564 +300 200 +402 302 +666 566 +1036 936 +841 741 +692 592 +317 217 +824 724 +319 219 +218 118 +932 832 +399 299 +919 819 +351 251 +587 487 +229 129 +573 473 +196 96 +341 241 +267 167 +164 64 +269 169 +616 516 +481 381 +957 857 +1076 976 +318 218 +867 767 +590 490 +937 837 +604 504 +507 407 +807 707 +303 203 +442 342 +487 387 +575 475 +835 735 +275 175 +806 706 +886 786 +435 335 +271 171 +140 40 +332 232 +921 821 +988 888 +231 131 +966 866 +259 159 +1076 976 +1078 978 +353 253 +153 53 +719 619 +949 849 +742 642 +578 478 +560 460 +119 19 +318 218 +330 230 +318 218 +553 453 +767 667 +436 336 +1049 949 +1031 931 +189 89 +688 588 +588 488 +549 449 +668 568 +666 566 +626 526 +0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_3_200_1000_1 b/scripts/Knapsack/Data/knapPI_3_200_1000_1 new file mode 100644 index 0000000..4f19afe --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_3_200_1000_1 @@ -0,0 +1,202 @@ +200 997 +585 485 +194 94 +426 326 +606 506 +348 248 +516 416 +521 421 +1092 992 +422 322 +749 649 +895 795 +337 237 +143 43 +557 457 +945 845 +915 815 +1055 955 +546 446 +352 252 +522 422 +109 9 +891 791 +1001 901 +459 359 +222 122 +767 667 +194 94 +698 598 +838 738 +107 7 +674 574 +644 544 +815 715 +434 334 +982 882 +866 766 +467 367 +1094 994 +1084 984 +993 893 +399 299 +733 633 +533 433 +231 131 +782 682 +528 428 +172 72 +800 700 +974 874 +717 617 +238 138 +974 874 +956 856 +820 720 +245 145 +519 419 +1095 995 +894 794 +629 529 +296 196 +299 199 +1097 997 +377 277 +216 116 +197 97 +1008 908 +819 719 +639 539 +342 242 +807 707 +207 107 +669 569 +222 122 +637 537 +170 70 +1031 931 +198 98 +826 726 +700 600 +587 487 +745 645 +872 772 +367 267 +613 513 +1072 972 +181 81 +995 895 +1043 943 +313 213 +158 58 +848 748 +403 303 +587 487 +864 764 +1023 923 +636 536 +129 29 +824 724 +774 674 +889 789 +640 540 +579 479 +654 554 +242 142 +567 467 +439 339 +146 46 +741 641 +810 710 +296 196 +653 553 +594 494 +291 191 +166 66 +824 724 +924 824 +830 730 +308 208 +1088 988 +811 711 +190 90 +900 800 +440 340 +414 314 +649 549 +389 289 +296 196 +501 401 +965 865 +566 466 +778 678 +789 689 +670 570 +933 833 +1036 936 +325 225 +822 722 +344 244 +751 651 +949 849 +223 123 +213 113 +531 431 +479 379 +608 508 +461 361 +685 585 +165 65 +953 853 +586 486 +742 642 +786 686 +1092 992 +386 286 +825 725 +989 889 +386 286 +124 24 +912 812 +591 491 +959 859 +991 891 +763 663 +190 90 +188 88 +281 181 +279 179 +314 214 +287 187 +117 17 +719 619 +572 472 +361 261 +518 418 +946 846 +519 419 +292 192 +456 356 +361 261 +782 682 +614 514 +406 306 +986 886 +301 201 +630 530 +485 385 +949 849 +1052 952 +394 294 +600 500 +899 799 +294 194 +491 391 +837 737 +430 330 +424 324 +398 298 +1092 992 +890 790 +324 224 +0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/scripts/Knapsack/Data/knapPI_3_500_1000_1 b/scripts/Knapsack/Data/knapPI_3_500_1000_1 new file mode 100644 index 0000000..bb76997 --- /dev/null +++ b/scripts/Knapsack/Data/knapPI_3_500_1000_1 @@ -0,0 +1,502 @@ +500 2517 +585 485 +194 94 +426 326 +606 506 +348 248 +516 416 +521 421 +1092 992 +422 322 +749 649 +895 795 +337 237 +143 43 +557 457 +945 845 +915 815 +1055 955 +546 446 +352 252 +522 422 +109 9 +891 791 +1001 901 +459 359 +222 122 +767 667 +194 94 +698 598 +838 738 +107 7 +674 574 +644 544 +815 715 +434 334 +982 882 +866 766 +467 367 +1094 994 +1084 984 +993 893 +399 299 +733 633 +533 433 +231 131 +782 682 +528 428 +172 72 +800 700 +974 874 +717 617 +238 138 +974 874 +956 856 +820 720 +245 145 +519 419 +1095 995 +894 794 +629 529 +296 196 +299 199 +1097 997 +377 277 +216 116 +197 97 +1008 908 +819 719 +639 539 +342 242 +807 707 +207 107 +669 569 +222 122 +637 537 +170 70 +1031 931 +198 98 +826 726 +700 600 +587 487 +745 645 +872 772 +367 267 +613 513 +1072 972 +181 81 +995 895 +1043 943 +313 213 +158 58 +848 748 +403 303 +587 487 +864 764 +1023 923 +636 536 +129 29 +824 724 +774 674 +889 789 +640 540 +579 479 +654 554 +242 142 +567 467 +439 339 +146 46 +741 641 +810 710 +296 196 +653 553 +594 494 +291 191 +166 66 +824 724 +924 824 +830 730 +308 208 +1088 988 +811 711 +190 90 +900 800 +440 340 +414 314 +649 549 +389 289 +296 196 +501 401 +965 865 +566 466 +778 678 +789 689 +670 570 +933 833 +1036 936 +325 225 +822 722 +344 244 +751 651 +949 849 +223 123 +213 113 +531 431 +479 379 +608 508 +461 361 +685 585 +165 65 +953 853 +586 486 +742 642 +786 686 +1092 992 +386 286 +825 725 +989 889 +386 286 +124 24 +912 812 +591 491 +959 859 +991 891 +763 663 +190 90 +188 88 +281 181 +279 179 +314 214 +287 187 +117 17 +719 619 +572 472 +361 261 +518 418 +946 846 +519 419 +292 192 +456 356 +361 261 +782 682 +614 514 +406 306 +986 886 +301 201 +630 530 +485 385 +949 849 +1052 952 +394 294 +600 500 +899 799 +294 194 +491 391 +837 737 +430 330 +424 324 +398 298 +1092 992 +890 790 +324 224 +375 275 +360 260 +926 826 +197 97 +172 72 +310 210 +966 866 +749 649 +1051 951 +1019 919 +848 748 +163 63 +785 685 +1058 958 +1056 956 +904 804 +664 564 +618 518 +283 183 +528 428 +500 400 +637 537 +821 721 +446 346 +307 207 +253 153 +423 323 +1071 971 +711 611 +762 662 +216 116 +297 197 +209 109 +191 91 +895 795 +629 529 +443 343 +226 126 +962 862 +847 747 +785 685 +569 469 +110 10 +870 770 +981 881 +1034 934 +1084 984 +823 723 +503 403 +995 895 +460 360 +668 568 +549 449 +272 172 +641 541 +1058 958 +372 272 +483 383 +977 877 +408 308 +459 359 +1070 970 +807 707 +683 583 +408 308 +148 48 +870 770 +1030 930 +130 30 +669 569 +308 208 +103 3 +411 311 +120 20 +200 100 +709 609 +1039 939 +987 887 +522 422 +925 825 +885 785 +1030 930 +470 370 +1004 904 +1089 989 +341 241 +1069 969 +479 379 +243 143 +476 376 +1072 972 +1062 962 +128 28 +989 889 +161 61 +543 443 +738 638 +316 216 +448 348 +438 338 +447 347 +260 160 +166 66 +506 406 +491 391 +259 159 +738 638 +131 31 +395 295 +304 204 +926 826 +520 420 +296 196 +253 153 +549 449 +525 425 +955 855 +431 331 +243 143 +665 565 +587 487 +938 838 +240 140 +109 9 +664 564 +1018 918 +715 615 +633 533 +235 135 +332 232 +664 564 +1057 957 +460 360 +691 591 +893 793 +676 576 +263 163 +846 746 +959 859 +477 377 +860 760 +958 858 +811 711 +186 86 +762 662 +534 434 +259 159 +658 558 +760 660 +379 279 +368 268 +940 840 +1048 948 +835 735 +415 315 +674 574 +776 676 +226 126 +441 341 +1012 912 +789 689 +839 739 +994 894 +921 821 +806 706 +725 625 +590 490 +1017 917 +578 478 +301 201 +771 671 +1093 993 +1032 932 +249 149 +999 899 +152 52 +337 237 +859 759 +287 187 +367 267 +572 472 +356 256 +872 772 +883 783 +198 98 +217 117 +1006 906 +616 516 +1011 911 +280 180 +735 635 +125 25 +325 225 +480 380 +923 823 +812 712 +264 164 +366 266 +443 343 +316 216 +832 732 +548 448 +602 502 +641 541 +840 740 +764 664 +676 576 +1054 954 +712 612 +826 726 +1002 902 +872 772 +554 454 +631 531 +511 411 +1043 943 +1073 973 +850 750 +803 703 +427 327 +950 850 +1017 917 +177 77 +105 5 +320 220 +213 113 +902 802 +1013 913 +503 403 +891 791 +281 181 +1098 998 +110 10 +959 859 +625 525 +445 345 +1019 919 +531 431 +768 668 +775 675 +627 527 +933 833 +562 462 +538 438 +391 291 +623 523 +705 605 +1016 916 +557 457 +520 420 +505 405 +215 115 +517 417 +760 660 +379 279 +361 261 +785 685 +872 772 +696 596 +488 388 +407 307 +864 764 +324 224 +943 843 +422 322 +306 206 +940 840 +507 407 +1075 975 +739 639 +501 401 +952 852 +191 91 +642 542 +427 327 +160 60 +430 330 +857 757 +282 182 +182 82 +703 603 +737 637 +893 793 +193 93 +715 615 +714 614 +833 733 +236 136 +964 864 +287 187 +116 16 +202 102 +963 863 +1072 972 +1087 987 +263 163 +406 306 +601 501 +134 34 +577 477 +0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 diff --git a/scripts/Knapsack/Knapsack.py b/scripts/Knapsack/Knapsack.py new file mode 100644 index 0000000..20e7382 --- /dev/null +++ b/scripts/Knapsack/Knapsack.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import locale +import os +from pathlib import Path +from typing import cast + +import numpy as np + +# for managing symbols +from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables +from sympy import Expr + +lambdas_method = [ + "upper_bound_only_positive", + "maximum_coefficient", + "VLM", + "MOMC", + "MOC", + "upper lower bound naive", + "upper lower bound posiform and negaform method", +] +lambdas_conf = [ + ("upper_bound_only_positive", "sequential penalty increase"), + ("maximum_coefficient", "sequential penalty increase"), + ("VLM", "sequential penalty increase"), + ("MOMC", "sequential penalty increase"), + ("MOC", "sequential penalty increase"), + ("upper lower bound naive", "sequential penalty increase"), + ("upper lower bound posiform and negaform method", "sequential penalty increase"), + ("upper_bound_only_positive", "scaled sequential penalty increase"), + ("maximum_coefficient", "scaled sequential penalty increase"), + ("VLM", "scaled sequential penalty increase"), + ("MOMC", "scaled sequential penalty increase"), + ("MOC", "scaled sequential penalty increase"), + ("upper lower bound naive", "scaled sequential penalty increase"), + ("upper lower bound posiform and negaform method", "scaled sequential penalty increase"), + ("upper_bound_only_positive", "binary search penalty algorithm"), + ("maximum_coefficient", "binary search penalty algorithm"), + ("VLM", "binary search penalty algorithm"), + ("MOMC", "binary search penalty algorithm"), + ("MOC", "binary search penalty algorithm"), + ("upper lower bound naive", "binary search penalty algorithm"), + ("upper lower bound posiform and negaform method", "binary search penalty algorithm"), +] + +files = os.listdir("Data/") +files = ["f3_l-d_kp_4_20"] +for file in files: + print(file) + with Path("./Data/" + file).open("r", encoding=locale.getpreferredencoding(False)) as f: + lines = f.readlines() + el = lines[0].split() + objects = int(el[0]) + W_max = float(el[1]) + w = [] + p = [] + for i in range(1, len(lines)): + el = lines[i].split() + p.append(float(el[0])) + w.append(float(el[1])) + p_arr = np.asarray(p) + w_arr = np.asarray(w) + + for lambdas in lambdas_method: + variables = Variables() + obj = variables.add_binary_variables_array("obj", [objects]) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(cast(Expr, np.dot(np.transpose(obj), p_arr)), minimization=False) + constraint = Constraints() + constraint.add_constraint(str(np.dot(np.transpose(obj), w_arr)) + " <= " + format(W_max)) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_simulated_annealing( + problem, lambda_strategy=lambdas, auto_setting=True, save_time=True, max_lambda_update=1 + ) + if not isinstance(solution, bool): + all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + solution.valid_solutions() + solution.wring_json_reports( + filename="simulated_annealing_knapsack_" + file + "_" + lambdas, problem_features=True + ) + + for lambdas_m, lambdas_update in lambdas_conf: + variables = Variables() + obj = variables.add_binary_variables_array("obj", [objects]) + objective_function = ObjectiveFunction() + objective_function.add_objective_function(cast(Expr, np.dot(np.transpose(obj), p_arr)), minimization=False) + constraint = Constraints() + constraint.add_constraint(str(np.dot(np.transpose(obj), w_arr)) + " <= " + format(W_max)) + problem = Problem() + problem.create_problem(variables, constraint, objective_function) + solver = Solver() + solution = solver.solve_simulated_annealing( + problem, + lambda_strategy=lambdas_m, + lambda_update_mechanism=lambdas_update, + auto_setting=True, + save_time=True, + max_lambda_update=1, + ) + if not isinstance(solution, bool): + all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + solution.valid_solutions() + solution.wring_json_reports( + filename="simulated_annealing_knapsack_" + file + "_" + lambdas_m + "_" + lambdas_update, + problem_features=True, + ) diff --git a/scripts/linear_regression/LinearRegression.py b/scripts/linear_regression/LinearRegression.py new file mode 100644 index 0000000..41496e9 --- /dev/null +++ b/scripts/linear_regression/LinearRegression.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +from typing import cast + +import numpy as np +import pandas as pd +from sklearn.decomposition import PCA +from sklearn.utils import shuffle + +# for managing symbols +from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables +from sympy import Expr + +df = pd.read_csv("iris_csv.csv") +df = shuffle(df) +d = len(df.columns) - 1 +N = len(df[df.keys()[1]]) +feat = 2 +X = np.zeros([N, d]) +Y = np.zeros(N) +TrainingPercentage = 0.7 +N_Traning = int(N * TrainingPercentage) +N_Test = N - N_Traning +i = 0 +for key in df: + j = 0 + if key != "class": + for el in df[key]: + X[j, i] = el + j += 1 + i += 1 + else: + for el in df[key]: + if el == "Iris-setosa": + Y[j] = 1 + else: + Y[j] = -1 + j += 1 +pca = PCA(n_components=feat) +X = pca.fit_transform(X=X, y=Y) +X_traning = np.hstack((X[:N_Traning, :], np.ones((N_Traning, 1)))) +X_test = np.hstack((X[N_Traning:, :], np.ones((N_Test, 1)))) + +Y_traning = Y[:N_Traning] +Y_test = Y[N_Traning:] +variables = Variables() +w = variables.add_continuous_variables_array("w", [feat + 1, 1], -0.25, 0.25, 0.25) +objective_function = ObjectiveFunction() +objective_function.add_objective_function( + cast( + Expr, + ( + np.dot(np.dot(np.dot(np.transpose(w), np.transpose(X_traning)), X_traning), w) + - 2 * np.dot(np.dot(np.transpose(w), np.transpose(X_traning)), Y_traning) + + np.dot(np.transpose(Y_traning), Y_traning) + )[0, 0], + ) +) +constraint = Constraints() +problem = Problem() +problem.create_problem(variables, constraint, objective_function) +solver = Solver() + +PredictionRes = {} + +solution = solver.solve_simulated_annealing( + problem, auto_setting=True, save_time=True, max_lambda_update=0, save_compilation_time=True +) +if not isinstance(solution, bool): + all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + solution.valid_solutions() + print(solution.best_energy) + solution.wring_json_reports(filename="simulated_annealing_linear_regression_Iris", problem_features=True) + w_conf = solution.best_solution["w"] + Y_obtained_training = np.dot(X_traning, w_conf) + TP_tr = 0 + TN_tr = 0 + FP_tr = 0 + FN_tr = 0 + for i in range(N_Traning): + if Y_obtained_training[i] > 0: + if Y_traning[i] == 1: + TP_tr += 1 + else: + FP_tr += 1 + elif Y_traning[i] == 1: + FN_tr += 1 + else: + TN_tr += 1 + + try: + Accuracy_tr = (TN_tr + TP_tr) / (TN_tr + TP_tr + FP_tr + FN_tr) + except ZeroDivisionError: + Accuracy_tr = 0 + + try: + Precision_tr = TP_tr / (TP_tr + FP_tr) + except ZeroDivisionError: + Precision_tr = 0 + + try: + Recall_tr = TP_tr / (TP_tr + FN_tr) + except ZeroDivisionError: + Recall_tr = 0 + + try: + F1_score_tr = 2 * Precision_tr * Recall_tr / (Precision_tr + Recall_tr) + except ZeroDivisionError: + F1_score_tr = 0 + + PredictionRes["Accuracy training"] = Accuracy_tr + PredictionRes["Precision training"] = Precision_tr + PredictionRes["Recall training"] = Recall_tr + PredictionRes["F1 training"] = F1_score_tr + Y_obtained_test = np.dot(X_test, w_conf) + print(Accuracy_tr, Precision_tr, Recall_tr) + TP_t = 0 + TN_t = 0 + FP_t = 0 + FN_t = 0 + for i in range(N_Test - 1): + if Y_obtained_test[i] > 0: + if Y_test[i] == 1: + TP_t += 1 + else: + FP_t += 1 + elif Y_test[i] == 1: + FN_t += 1 + else: + TN_t += 1 + + try: + Accuracy_t = (TN_t + TP_t) / (TN_t + TP_t + FP_t + FN_t) + except ZeroDivisionError: + Accuracy_t = 0 + + try: + Precision_t = TP_t / (TP_t + FP_t) + except ZeroDivisionError: + Precision_t = 0 + + try: + Recall_t = TP_t / (TP_t + FN_t) + except ZeroDivisionError: + Recall_t = 0 + + try: + F1_score_t = 2 * Precision_t * Recall_t / (Precision_t + Recall_t) + except ZeroDivisionError: + F1_score_t = 0 + print(Accuracy_t, Precision_t, Recall_t) + PredictionRes["Accuracy test"] = Accuracy_t + PredictionRes["Precision test"] = Precision_t + PredictionRes["Recall test"] = Recall_t + PredictionRes["F1 test"] = F1_score_t + + +df1 = pd.DataFrame.from_dict(PredictionRes, orient="index") +df1.to_csv("PredictionResSimulatedAnnealing.csv") diff --git a/scripts/linear_regression/iris_csv.csv b/scripts/linear_regression/iris_csv.csv new file mode 100644 index 0000000..3c63137 --- /dev/null +++ b/scripts/linear_regression/iris_csv.csv @@ -0,0 +1,101 @@ +sepallength,sepalwidth,petallength,petalwidth,class +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3.0,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5.0,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5.0,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3.0,1.4,0.1,Iris-setosa +4.3,3.0,1.1,0.1,Iris-setosa +5.8,4.0,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1.0,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5.0,3.0,1.6,0.2,Iris-setosa +5.0,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.0,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3.0,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5.0,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5.0,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3.0,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5.0,3.3,1.4,0.2,Iris-setosa +7.0,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4.0,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1.0,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5.0,2.0,3.5,1.0,Iris-versicolor +5.9,3.0,4.2,1.5,Iris-versicolor +6.0,2.2,4.0,1.0,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3.0,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1.0,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4.0,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3.0,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3.0,5.0,1.7,Iris-versicolor +6.0,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1.0,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1.0,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6.0,2.7,5.1,1.6,Iris-versicolor +5.4,3.0,4.5,1.5,Iris-versicolor +6.0,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3.0,4.1,1.3,Iris-versicolor +5.5,2.5,4.0,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3.0,4.6,1.4,Iris-versicolor +5.8,2.6,4.0,1.2,Iris-versicolor +5.0,2.3,3.3,1.0,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3.0,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3.0,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor From a2ad1abe26c53c0317eedaccd8203e13e1f52297 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 18:32:45 +0000 Subject: [PATCH 80/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/Knapsack/Knapsack.py | 2 +- scripts/linear_regression/LinearRegression.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Knapsack/Knapsack.py b/scripts/Knapsack/Knapsack.py index 20e7382..3b34e57 100644 --- a/scripts/Knapsack/Knapsack.py +++ b/scripts/Knapsack/Knapsack.py @@ -6,10 +6,10 @@ from typing import cast import numpy as np +from sympy import Expr # for managing symbols from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables -from sympy import Expr lambdas_method = [ "upper_bound_only_positive", diff --git a/scripts/linear_regression/LinearRegression.py b/scripts/linear_regression/LinearRegression.py index 41496e9..d7c5543 100644 --- a/scripts/linear_regression/LinearRegression.py +++ b/scripts/linear_regression/LinearRegression.py @@ -6,10 +6,10 @@ import pandas as pd from sklearn.decomposition import PCA from sklearn.utils import shuffle +from sympy import Expr # for managing symbols from mqt.qao import Constraints, ObjectiveFunction, Problem, Solver, Variables -from sympy import Expr df = pd.read_csv("iris_csv.csv") df = shuffle(df) From 68592dc3928a1c1db5b70f39e6673126f0ff3fce Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 6 Jun 2024 11:46:41 +0200 Subject: [PATCH 81/89] Update bibliography --- CITATION.bib | 6 +++--- docs/refs.bib | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CITATION.bib b/CITATION.bib index 13f0a82..9a41c1e 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -1,6 +1,6 @@ -@MISC{volpe2024towards, +@INPROCEEDINGS{volpe2024towards, AUTHOR = {D.Volpe and N. Quetschlich and M. Graziano and G. Turvani and R. Wille}, TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, YEAR = {2024}, - BOOKTITLE = {2024 IEEE International Conference on Quantum Software (QSW)}, -} + BOOKTITLE = {IEEE International Conference on Quantum Software (QSW)}, +} \ No newline at end of file diff --git a/docs/refs.bib b/docs/refs.bib index 13f0a82..42f9a00 100644 --- a/docs/refs.bib +++ b/docs/refs.bib @@ -1,6 +1,6 @@ -@MISC{volpe2024towards, +@INPROCEEDINGS{volpe2024towards, AUTHOR = {D.Volpe and N. Quetschlich and M. Graziano and G. Turvani and R. Wille}, TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, YEAR = {2024}, - BOOKTITLE = {2024 IEEE International Conference on Quantum Software (QSW)}, + BOOKTITLE = {IEEE International Conference on Quantum Software (QSW)}, } From 0ed50a05952dd3eda62ac1010307231e91b24332 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 09:48:05 +0000 Subject: [PATCH 82/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CITATION.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CITATION.bib b/CITATION.bib index 9a41c1e..42f9a00 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -3,4 +3,4 @@ @INPROCEEDINGS{volpe2024towards TITLE = {{Towards an Automatic Framework for Solving Optimization Problems with Quantum Computers}}, YEAR = {2024}, BOOKTITLE = {IEEE International Conference on Quantum Software (QSW)}, -} \ No newline at end of file +} From 909339986d05c853cecd76bf92dd6428029a4b8c Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 6 Jun 2024 11:51:30 +0200 Subject: [PATCH 83/89] Readme fix --- requirements.txt | 252 ++++++++++++++++++ .../PredictionResSimulatedAnnealing.csv | 9 + ...ated_annealing_linear_regression_Iris.json | 1 + 3 files changed, 262 insertions(+) create mode 100644 requirements.txt create mode 100644 scripts/linear_regression/PredictionResSimulatedAnnealing.csv create mode 100644 scripts/linear_regression/simulated_annealing_linear_regression_Iris.json diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..398cf59 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,252 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements.txt +annotated-types==0.7.0 + # via pydantic +authlib==1.3.0 + # via dwave-cloud-client +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via cryptography +charset-normalizer==3.3.2 + # via requests +clarabel==0.8.1 + # via cvxpy +click==8.1.7 + # via dwave-cloud-client +colorama==0.4.6 + # via + # click + # pytest +contourpy==1.2.1 + # via matplotlib +cryptography==42.0.7 + # via + # authlib + # pyspnego + # requests-ntlm +cvxpy==1.5.1 + # via pyportfolioopt +cycler==0.12.1 + # via matplotlib +dill==0.3.8 + # via qiskit +dimod==0.12.14 + # via + # mqt-qao (pyproject.toml) + # dwave-networkx + # dwave-preprocessing + # dwave-samplers + # dwave-system +diskcache==5.6.3 + # via dwave-cloud-client +docplex==2.27.239 + # via + # mqt-qao (pyproject.toml) + # qiskit-optimization +dwave-cloud-client==0.11.4 + # via dwave-system +dwave-networkx==0.8.14 + # via + # dwave-system + # minorminer +dwave-preprocessing==0.6.5 + # via dwave-system +dwave-samplers==1.2.0 + # via + # mqt-qao (pyproject.toml) + # dwave-system +dwave-system==1.24.0 + # via mqt-qao (pyproject.toml) +ecos==2.0.13 + # via cvxpy +fasteners==0.19 + # via minorminer +fonttools==4.51.0 + # via matplotlib +homebase==1.0.1 + # via + # dwave-cloud-client + # dwave-system + # minorminer +idna==3.7 + # via requests +importlib-metadata==7.1.0 + # via dwave-cloud-client +iniconfig==2.0.0 + # via pytest +joblib==1.4.2 + # via scikit-learn +kiwisolver==1.4.5 + # via matplotlib +markupsafe==2.1.5 + # via werkzeug +matplotlib==3.9.0 + # via mqt-qao (pyproject.toml) +minorminer==0.2.13 + # via dwave-system +mpmath==1.3.0 + # via sympy +networkx==3.3 + # via + # dwave-networkx + # dwave-samplers + # minorminer + # qiskit-optimization +numpy==1.26.4 + # via + # mqt-qao (pyproject.toml) + # clarabel + # contourpy + # cvxpy + # dimod + # dwave-networkx + # dwave-preprocessing + # dwave-samplers + # dwave-system + # ecos + # matplotlib + # minorminer + # osqp + # pandas + # pyportfolioopt + # qdldl + # qiskit + # qiskit-algorithms + # qiskit-ibm-provider + # qiskit-optimization + # qubovert + # rustworkx + # scikit-learn + # scipy + # scs +osqp==0.6.7 + # via cvxpy +packaging==24.0 + # via + # dwave-cloud-client + # matplotlib + # pytest +pandas==2.2.2 + # via + # mqt-qao (pyproject.toml) + # pyportfolioopt +pbr==6.0.0 + # via stevedore +pillow==10.3.0 + # via matplotlib +plucky==0.4.3 + # via dwave-cloud-client +pluggy==1.5.0 + # via pytest +pycparser==2.22 + # via cffi +pydantic==2.7.1 + # via dwave-cloud-client +pydantic-core==2.18.2 + # via pydantic +pyparsing==3.1.2 + # via matplotlib +pyportfolioopt==1.5.5 + # via mqt-qao (pyproject.toml) +pysocks==1.7.1 + # via requests +pyspnego==0.10.2 + # via requests-ntlm +pytest==8.2.1 + # via mqt-qao (pyproject.toml) +python-dateutil==2.9.0.post0 + # via + # dwave-cloud-client + # matplotlib + # pandas + # qiskit + # qiskit-ibm-provider +pytz==2024.1 + # via pandas +qdldl==0.1.7.post2 + # via osqp +qiskit==1.1.0 + # via + # mqt-qao (pyproject.toml) + # qiskit-algorithms + # qiskit-ibm-provider + # qiskit-optimization +qiskit-algorithms==0.3.0 + # via qiskit-optimization +qiskit-ibm-provider==0.11.0 + # via mqt-qao (pyproject.toml) +qiskit-optimization==0.6.1 + # via mqt-qao (pyproject.toml) +qubovert==1.2.5 + # via mqt-qao (pyproject.toml) +rectangle-packer==2.0.2 + # via minorminer +requests==2.32.2 + # via + # dwave-cloud-client + # qiskit-ibm-provider + # requests-ntlm +requests-ntlm==1.2.0 + # via qiskit-ibm-provider +rustworkx==0.14.2 + # via qiskit +scikit-learn==1.5.0 + # via mqt-qao (pyproject.toml) +scipy==1.13.1 + # via + # clarabel + # cvxpy + # dwave-system + # ecos + # minorminer + # osqp + # pyportfolioopt + # qdldl + # qiskit + # qiskit-algorithms + # qiskit-optimization + # scikit-learn + # scs +scs==3.2.4.post1 + # via cvxpy +setuptools==70.0.0 + # via qiskit-optimization +six==1.16.0 + # via + # docplex + # python-dateutil +sspilib==0.1.0 + # via pyspnego +stevedore==5.2.0 + # via qiskit +symengine==0.11.0 + # via qiskit +sympy==1.12 + # via + # mqt-qao (pyproject.toml) + # qiskit +threadpoolctl==3.5.0 + # via scikit-learn +typing-extensions==4.11.0 + # via + # dwave-cloud-client + # pydantic + # pydantic-core + # qiskit + # qiskit-ibm-provider +tzdata==2024.1 + # via pandas +urllib3==2.2.1 + # via + # dwave-cloud-client + # qiskit-ibm-provider + # requests +websocket-client==1.8.0 + # via qiskit-ibm-provider +websockets==12.0 + # via qiskit-ibm-provider +werkzeug==3.0.3 + # via dwave-cloud-client +zipp==3.18.2 + # via importlib-metadata diff --git a/scripts/linear_regression/PredictionResSimulatedAnnealing.csv b/scripts/linear_regression/PredictionResSimulatedAnnealing.csv new file mode 100644 index 0000000..53de89d --- /dev/null +++ b/scripts/linear_regression/PredictionResSimulatedAnnealing.csv @@ -0,0 +1,9 @@ +,0 +Accuracy training,1.0 +Precision training,1.0 +Recall training,1.0 +F1 training,1.0 +Accuracy test,1.0 +Precision test,1.0 +Recall test,1.0 +F1 test,1.0 diff --git a/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json b/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json new file mode 100644 index 0000000..8bdb4a3 --- /dev/null +++ b/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json @@ -0,0 +1 @@ +{"solver name": "Simulated annealer", "num reads": 100, "annealing time": 16, "compilation time": 6167900.0, "energies": [24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713], "best energy": 24.613856939869713, "cost functions energy best solution": {"195.845749787118*w_0_0**2 + 6.6681082873237*w_0_0*w_1_0 + 26.613062206613*w_0_0*w_2_0 + 226.263839976905*w_0_0 + 15.5869513719764*w_1_0**2 + 2.54624645289538*w_1_0*w_2_0 - 6.47188048155888*w_1_0 + 70.0*w_2_0**2 + 12.0*w_2_0 + 70.0": 24.61385693986972}, "constraint satisfaction best solution": true, "best solution": {"w": [[-0.25], [0.25], [0.0]]}, "solutions": [{"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}], "best solution binary": {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, "solutions binary": [{"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}], "time": 20970.0, "valid solution rate": {"0": 1.0}, "p range": 1.0, "TTS": 20970.0, "qubo": {"(0, 1)": 24.48071872338975, "(0,)": 42.24552747666033, "()": 31.88076750778388, "(1,)": 42.24552747666033, "(0, 2)": 0.41675676795773126, "(0, 3)": 0.41675676795773126, "(2,)": -3.168051752401938, "(3,)": -3.168051752401938, "(1, 2)": 0.41675676795773126, "(1, 3)": 0.41675676795773126, "(0, 4)": 1.6633163879133126, "(0, 5)": 1.6633163879133126, "(4,)": -3.197456791219274, "(5,)": -3.197456791219274, "(1, 4)": 1.6633163879133126, "(1, 5)": 1.6633163879133126, "(2, 3)": 1.94836892149705, "(2, 4)": 0.15914040330596124, "(2, 5)": 0.15914040330596124, "(3, 4)": 0.15914040330596124, "(3, 5)": 0.15914040330596124, "(4, 5)": 8.75}, "qubo num var": 6, "qubo contributions": {"2": 15, "1": 6, "0": 1}, "qubo contributions average": {"2": 0.0, "1": 0.0, "0": 31.88076750778388}, "qubo contributions variance": {"2": 0.0, "1": 0.0, "0": 0.0}, "qubo coefficient average": 1.449125795808358, "qubo coefficient variance": 44.09927701362135, "pubo": {"('b0', 'b1')": 24.48071872338975, "('b0',)": 42.24552747666033, "()": 31.88076750778388, "('b1',)": 42.24552747666033, "('b0', 'b2')": 0.41675676795773126, "('b0', 'b3')": 0.41675676795773126, "('b2',)": -3.168051752401938, "('b3',)": -3.168051752401938, "('b1', 'b2')": 0.41675676795773126, "('b1', 'b3')": 0.41675676795773126, "('b0', 'b4')": 1.6633163879133126, "('b0', 'b5')": 1.6633163879133126, "('b4',)": -3.197456791219274, "('b5',)": -3.197456791219274, "('b1', 'b4')": 1.6633163879133126, "('b1', 'b5')": 1.6633163879133126, "('b2', 'b3')": 1.94836892149705, "('b2', 'b4')": 0.15914040330596124, "('b2', 'b5')": 0.15914040330596124, "('b3', 'b4')": 0.15914040330596124, "('b3', 'b5')": 0.15914040330596124, "('b4', 'b5')": 8.75}, "num var": 6, "pubo contributions": {"2": 15, "1": 6, "0": 1}, "pubo contributions average": {"2": 2.942396125439655, "1": 11.960006311013037, "0": 31.88076750778388}, "pubo contributions variance": {"2": 37.44408929297084, "1": 458.6065402468196, "0": 0.0}, "pubo coefficient average": 6.717124875248044, "pubo coefficient variance": 196.59840831499267, "lambdas": []} \ No newline at end of file From ed2eb3fa18c92f6901156641c2a2856e456561eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 09:52:52 +0000 Subject: [PATCH 84/89] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ated_annealing_linear_regression_Iris.json | 334 +++++++++++++++++- 1 file changed, 333 insertions(+), 1 deletion(-) diff --git a/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json b/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json index 8bdb4a3..273d4cc 100644 --- a/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json +++ b/scripts/linear_regression/simulated_annealing_linear_regression_Iris.json @@ -1 +1,333 @@ -{"solver name": "Simulated annealer", "num reads": 100, "annealing time": 16, "compilation time": 6167900.0, "energies": [24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713, 24.613856939869713], "best energy": 24.613856939869713, "cost functions energy best solution": {"195.845749787118*w_0_0**2 + 6.6681082873237*w_0_0*w_1_0 + 26.613062206613*w_0_0*w_2_0 + 226.263839976905*w_0_0 + 15.5869513719764*w_1_0**2 + 2.54624645289538*w_1_0*w_2_0 - 6.47188048155888*w_1_0 + 70.0*w_2_0**2 + 12.0*w_2_0 + 70.0": 24.61385693986972}, "constraint satisfaction best solution": true, "best solution": {"w": [[-0.25], [0.25], [0.0]]}, "solutions": [{"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}, {"w": [[-0.25], [0.25], [0.0]]}], "best solution binary": {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, "solutions binary": [{"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}, {"b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0}], "time": 20970.0, "valid solution rate": {"0": 1.0}, "p range": 1.0, "TTS": 20970.0, "qubo": {"(0, 1)": 24.48071872338975, "(0,)": 42.24552747666033, "()": 31.88076750778388, "(1,)": 42.24552747666033, "(0, 2)": 0.41675676795773126, "(0, 3)": 0.41675676795773126, "(2,)": -3.168051752401938, "(3,)": -3.168051752401938, "(1, 2)": 0.41675676795773126, "(1, 3)": 0.41675676795773126, "(0, 4)": 1.6633163879133126, "(0, 5)": 1.6633163879133126, "(4,)": -3.197456791219274, "(5,)": -3.197456791219274, "(1, 4)": 1.6633163879133126, "(1, 5)": 1.6633163879133126, "(2, 3)": 1.94836892149705, "(2, 4)": 0.15914040330596124, "(2, 5)": 0.15914040330596124, "(3, 4)": 0.15914040330596124, "(3, 5)": 0.15914040330596124, "(4, 5)": 8.75}, "qubo num var": 6, "qubo contributions": {"2": 15, "1": 6, "0": 1}, "qubo contributions average": {"2": 0.0, "1": 0.0, "0": 31.88076750778388}, "qubo contributions variance": {"2": 0.0, "1": 0.0, "0": 0.0}, "qubo coefficient average": 1.449125795808358, "qubo coefficient variance": 44.09927701362135, "pubo": {"('b0', 'b1')": 24.48071872338975, "('b0',)": 42.24552747666033, "()": 31.88076750778388, "('b1',)": 42.24552747666033, "('b0', 'b2')": 0.41675676795773126, "('b0', 'b3')": 0.41675676795773126, "('b2',)": -3.168051752401938, "('b3',)": -3.168051752401938, "('b1', 'b2')": 0.41675676795773126, "('b1', 'b3')": 0.41675676795773126, "('b0', 'b4')": 1.6633163879133126, "('b0', 'b5')": 1.6633163879133126, "('b4',)": -3.197456791219274, "('b5',)": -3.197456791219274, "('b1', 'b4')": 1.6633163879133126, "('b1', 'b5')": 1.6633163879133126, "('b2', 'b3')": 1.94836892149705, "('b2', 'b4')": 0.15914040330596124, "('b2', 'b5')": 0.15914040330596124, "('b3', 'b4')": 0.15914040330596124, "('b3', 'b5')": 0.15914040330596124, "('b4', 'b5')": 8.75}, "num var": 6, "pubo contributions": {"2": 15, "1": 6, "0": 1}, "pubo contributions average": {"2": 2.942396125439655, "1": 11.960006311013037, "0": 31.88076750778388}, "pubo contributions variance": {"2": 37.44408929297084, "1": 458.6065402468196, "0": 0.0}, "pubo coefficient average": 6.717124875248044, "pubo coefficient variance": 196.59840831499267, "lambdas": []} \ No newline at end of file +{ + "solver name": "Simulated annealer", + "num reads": 100, + "annealing time": 16, + "compilation time": 6167900.0, + "energies": [ + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713, 24.613856939869713, 24.613856939869713, + 24.613856939869713 + ], + "best energy": 24.613856939869713, + "cost functions energy best solution": { + "195.845749787118*w_0_0**2 + 6.6681082873237*w_0_0*w_1_0 + 26.613062206613*w_0_0*w_2_0 + 226.263839976905*w_0_0 + 15.5869513719764*w_1_0**2 + 2.54624645289538*w_1_0*w_2_0 - 6.47188048155888*w_1_0 + 70.0*w_2_0**2 + 12.0*w_2_0 + 70.0": 24.61385693986972 + }, + "constraint satisfaction best solution": true, + "best solution": { "w": [[-0.25], [0.25], [0.0]] }, + "solutions": [ + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] }, + { "w": [[-0.25], [0.25], [0.0]] } + ], + "best solution binary": { + "b0": 0.0, + "b1": 0.0, + "b2": 1.0, + "b3": 1.0, + "b4": 0.0, + "b5": 1.0 + }, + "solutions binary": [ + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 0.0, "b5": 1.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 }, + { "b0": 0.0, "b1": 0.0, "b2": 1.0, "b3": 1.0, "b4": 1.0, "b5": 0.0 } + ], + "time": 20970.0, + "valid solution rate": { "0": 1.0 }, + "p range": 1.0, + "TTS": 20970.0, + "qubo": { + "(0, 1)": 24.48071872338975, + "(0,)": 42.24552747666033, + "()": 31.88076750778388, + "(1,)": 42.24552747666033, + "(0, 2)": 0.41675676795773126, + "(0, 3)": 0.41675676795773126, + "(2,)": -3.168051752401938, + "(3,)": -3.168051752401938, + "(1, 2)": 0.41675676795773126, + "(1, 3)": 0.41675676795773126, + "(0, 4)": 1.6633163879133126, + "(0, 5)": 1.6633163879133126, + "(4,)": -3.197456791219274, + "(5,)": -3.197456791219274, + "(1, 4)": 1.6633163879133126, + "(1, 5)": 1.6633163879133126, + "(2, 3)": 1.94836892149705, + "(2, 4)": 0.15914040330596124, + "(2, 5)": 0.15914040330596124, + "(3, 4)": 0.15914040330596124, + "(3, 5)": 0.15914040330596124, + "(4, 5)": 8.75 + }, + "qubo num var": 6, + "qubo contributions": { "2": 15, "1": 6, "0": 1 }, + "qubo contributions average": { "2": 0.0, "1": 0.0, "0": 31.88076750778388 }, + "qubo contributions variance": { "2": 0.0, "1": 0.0, "0": 0.0 }, + "qubo coefficient average": 1.449125795808358, + "qubo coefficient variance": 44.09927701362135, + "pubo": { + "('b0', 'b1')": 24.48071872338975, + "('b0',)": 42.24552747666033, + "()": 31.88076750778388, + "('b1',)": 42.24552747666033, + "('b0', 'b2')": 0.41675676795773126, + "('b0', 'b3')": 0.41675676795773126, + "('b2',)": -3.168051752401938, + "('b3',)": -3.168051752401938, + "('b1', 'b2')": 0.41675676795773126, + "('b1', 'b3')": 0.41675676795773126, + "('b0', 'b4')": 1.6633163879133126, + "('b0', 'b5')": 1.6633163879133126, + "('b4',)": -3.197456791219274, + "('b5',)": -3.197456791219274, + "('b1', 'b4')": 1.6633163879133126, + "('b1', 'b5')": 1.6633163879133126, + "('b2', 'b3')": 1.94836892149705, + "('b2', 'b4')": 0.15914040330596124, + "('b2', 'b5')": 0.15914040330596124, + "('b3', 'b4')": 0.15914040330596124, + "('b3', 'b5')": 0.15914040330596124, + "('b4', 'b5')": 8.75 + }, + "num var": 6, + "pubo contributions": { "2": 15, "1": 6, "0": 1 }, + "pubo contributions average": { + "2": 2.942396125439655, + "1": 11.960006311013037, + "0": 31.88076750778388 + }, + "pubo contributions variance": { + "2": 37.44408929297084, + "1": 458.6065402468196, + "0": 0.0 + }, + "pubo coefficient average": 6.717124875248044, + "pubo coefficient variance": 196.59840831499267, + "lambdas": [] +} From 467310cf9c36ca542ff96e8fcc4e28ae3569af45 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 6 Jun 2024 11:55:57 +0200 Subject: [PATCH 85/89] Documentation --- docs/Constraints.rst | 2 +- docs/Problem.rst | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/Constraints.rst b/docs/Constraints.rst index c3fbc55..f3aac6d 100644 --- a/docs/Constraints.rst +++ b/docs/Constraints.rst @@ -16,7 +16,7 @@ Types of constraints supported: - *Xor constraint* among binary variables, i.e. a xor b = c imposed with 2ab - 2(a+b)c - 4(a+b)\_aux+4_aux c +a+b+c+4+\_aux Constraints declarations ----------------------- +------------------------ The class provides methods to declare variables: diff --git a/docs/Problem.rst b/docs/Problem.rst index 1ba6996..4f85945 100644 --- a/docs/Problem.rst +++ b/docs/Problem.rst @@ -15,16 +15,16 @@ The class provides a method for declaring the problem: and a method for obtaining the HUBO or PUBO formulation of the problem as qubovert PUBO object: -- * write_the_final_cost_function( lambda_strategy: str, lambda_value: float = 1)* : This method is used to obtain the HUBO or PUBO formulation of the problem as qubovert PUBO object. The method takes two arguments: +- *write_the_final_cost_function( lambda_strategy: str, lambda_value: float = 1)* : This method is used to obtain the HUBO or PUBO formulation of the problem as qubovert PUBO object. The method takes two arguments: - *lambda_strategy* The strategy to be used for the conversion of the problem to HUBO or PUBO. The possible values are: - - 'upper_bound_only_positive' - - 'maximum_coefficient' - - 'VLM' - - 'MOC' - - 'MOMC' - - 'upper lower bound naive' - - 'upper lower bound posiform and negaform method' - - 'manual' + - upper_bound_only_positive + - maximum_coefficient + - VLM + - MOC + - MOMC + - upper lower bound naive + - upper lower bound posiform and negaform method + - manual - *lambda_value* The value of the lambda parameter if the use want to manually select it. The default value is 1.0. Example: From 4045f9a9c9860c62746e0ba2ada4c38bc550c5fb Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 6 Jun 2024 11:58:42 +0200 Subject: [PATCH 86/89] Documentation --- docs/Solution.rst | 2 +- docs/Solver.rst | 150 +++++++++++++++++++++++----------------------- docs/index.rst | 4 +- 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/docs/Solution.rst b/docs/Solution.rst index f38295e..ca62076 100644 --- a/docs/Solution.rst +++ b/docs/Solution.rst @@ -39,7 +39,7 @@ The class has the following methods for helping users in analyzing the solution: - *tts(ref_value: float | None = None, target_probability: float = 0.99)*: This method is used to get the time-to-solution of the best solution obtained in all the runs, which is the time required to obtain a solution with a certain probability. The parameters are: - ref_value: float | None, i.e. the reference value to calculate the p-range - target_probability: float, i.e. the target probability to calculate the time-to-solution --*wring_json_reports(filename: str = "report", weak: bool = False, ref_value: float | None = None, target_probability: float = 0.99, problem_features: bool = False)* : This method is used to write the reports in json format. The parameters are: +- *wring_json_reports(filename: str = "report", weak: bool = False, ref_value: float | None = None, target_probability: float = 0.99, problem_features: bool = False)* : This method is used to write the reports in json format. The parameters are: - filename: str, i.e. the name of the file where the report will be saved - weak: bool, i.e. whether to consider in the evaluation the weak constraints - ref_value: float | None, i.e. the reference value to calculate the p-range diff --git a/docs/Solver.rst b/docs/Solver.rst index f3ab436..bddd3b8 100644 --- a/docs/Solver.rst +++ b/docs/Solver.rst @@ -36,21 +36,21 @@ The class provides for exploiting the solver: lambda_value: float = 1.0, save_time: bool = False, ) : Solve the problem using the simulated annealer. The parameters are: - - *problem*: the problem to solve - - *auto_setting*: if True, the parameters are automatically set - - *beta_range*: the range of beta values to use - - *num_reads*: the number of reads - - *annealing_time*: the annealing time - - *num_sweeps_per_beta*: the number of sweeps per beta - - *beta_schedule_type*: the beta schedule type - - *seed*: the seed - - *initial_states*: the initial states - - *initial_states_generator*: the initial states generator - - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied - - *lambda_update_mechanism*: the lambda update mechanism among: - - *sequential penalty increase* - - *scaled sequential penalty increase* - - *binary search penalty algorithm* + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *beta_range*: the range of beta values to use + - *num_reads*: the number of reads + - *annealing_time*: the annealing time + - *num_sweeps_per_beta*: the number of sweeps per beta + - *beta_schedule_type*: the beta schedule type + - *seed*: the seed + - *initial_states*: the initial states + - *initial_states_generator*: the initial states generator + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* - solve_dwave_quantum_annealer( problem: Problem, token: str, @@ -74,26 +74,26 @@ The class provides for exploiting the solver: save_time: bool = False, save_compilation_time: bool = False, ) : Solve the problem using the D-Wave quantum annealer. The parameters are: - - *problem*: the problem to solve - - *token*: the token to access the D-Wave API - - *auto_setting*: if True, the parameters are automatically set - - *failover*: if True, the failover is enabled - - *config_file*: the configuration file - - *endpoint*: the endpoint - - *solver*: the solver to use - - *annealing_time_scheduling*: the annealing time scheduling - - *num_reads*: the number of reads - - *auto_scale*: if True, the problem is automatically scaled - - *flux_drift_compensation*: if True, the flux drift compensation is enabled - - *initial_state*: the initial state - - *programming_thermalization*: the programming thermalization - - *readout_thermalization*: the readout thermalization - - *reduce_intersample_correlation*: if True, the intersample correlation is reduced - - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied - - *lambda_update_mechanism*: the lambda update mechanism among: - - *sequential penalty increase* - - *scaled sequential penalty increase* - - *binary search penalty algorithm* + - *problem*: the problem to solve + - *token*: the token to access the D-Wave API + - *auto_setting*: if True, the parameters are automatically set + - *failover*: if True, the failover is enabled + - *config_file*: the configuration file + - *endpoint*: the endpoint + - *solver*: the solver to use + - *annealing_time_scheduling*: the annealing time scheduling + - *num_reads*: the number of reads + - *auto_scale*: if True, the problem is automatically scaled + - *flux_drift_compensation*: if True, the flux drift compensation is enabled + - *initial_state*: the initial state + - *programming_thermalization*: the programming thermalization + - *readout_thermalization*: the readout thermalization + - *reduce_intersample_correlation*: if True, the intersample correlation is reduced + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* - solve_grover_adaptive_search_qubo( problem: Problem, auto_setting: bool = False, @@ -109,18 +109,18 @@ The class provides for exploiting the solver: save_time: bool = False, save_compilation_time: bool = False, ) : Solve the problem using the Grover Adaptive Search. The parameters are: - - *problem*: the problem to solve - - *auto_setting*: if True, the parameters are automatically set - - *qubit_values*: the number of qubit values, if the user want to specify it manually - - *coeff_precision*: the coefficient precision - - *threshold*: the threshold - - *num_runs*: the number of runs - - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied - - *boundaries_estimation_method*: the boundaries estimation method for estimating the necessary number of qubit value - - *lambda_update_mechanism*: the lambda update mechanism among: - - *sequential penalty increase* - - *scaled sequential penalty increase* - - *binary search penalty algorithm* + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *qubit_values*: the number of qubit values, if the user want to specify it manually + - *coeff_precision*: the coefficient precision + - *threshold*: the threshold + - *num_runs*: the number of runs + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *boundaries_estimation_method*: the boundaries estimation method for estimating the necessary number of qubit value + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* - solve_qaoa_qubo( problem: Problem, auto_setting: bool = False, @@ -139,21 +139,21 @@ The class provides for exploiting the solver: save_time: bool = False, save_compilation_time: bool = False, ) : Solve the problem using the Quantum Approximate Optimization Algorithm. The parameters are: - - *problem*: the problem to solve - - *auto_setting*: if True, the parameters are automatically set - - *num_runs*: the number of runs - - *optimizer*: the optimizer - - *reps*: the number of repetitions - - *initial_state*: the initial state - - *mixer*: the mixer - - *initial_point*: the initial point - - *aggregation*: the aggregation function - - *callback*: the callback function - - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied - - *lambda_update_mechanism*: the lambda update mechanism among: - - *sequential penalty increase* - - *scaled sequential penalty increase* - - *binary search penalty algorithm* + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *num_runs*: the number of runs + - *optimizer*: the optimizer + - *reps*: the number of repetitions + - *initial_state*: the initial state + - *mixer*: the mixer + - *initial_point*: the initial point + - *aggregation*: the aggregation function + - *callback*: the callback function + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* - solve_vqe_qubo( self, problem: Problem, @@ -171,19 +171,19 @@ The class provides for exploiting the solver: save_time: bool = False, save_compilation_time: bool = False, ) : Solve the problem using the Variational Quantum Eigensolver. The parameters are: - - *problem*: the problem to solve - - *auto_setting*: if True, the parameters are automatically set - - *num_runs*: the number of runs - - *optimizer*: the optimizer - - *ansatz*: the ansatz - - *initial_point*: the initial point - - *aggregation*: the aggregation function - - *callback*: the callback function - - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied - - *lambda_update_mechanism*: the lambda update mechanism among: - - *sequential penalty increase* - - *scaled sequential penalty increase* - - *binary search penalty algorithm* + - *problem*: the problem to solve + - *auto_setting*: if True, the parameters are automatically set + - *num_runs*: the number of runs + - *optimizer*: the optimizer + - *ansatz*: the ansatz + - *initial_point*: the initial point + - *aggregation*: the aggregation function + - *callback*: the callback function + - *max_lambda_update*: the maximum lambda update if the constraints are not satisfied + - *lambda_update_mechanism*: the lambda update mechanism among: + - *sequential penalty increase* + - *scaled sequential penalty increase* + - *binary search penalty algorithm* For each of them, the outcome is a Solution object. diff --git a/docs/index.rst b/docs/index.rst index 30c6fd7..a21d86b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,11 +30,11 @@ If you are interested in the theory behind MQT Quantum Auto Optimizer, have a lo Quickstart Usage - Variables + Variable Constraints ObjectiveFunction Problem - Solvers + Solver Solution References From 95c07b3efc092c4be3639bd8dd6db22d1f599327 Mon Sep 17 00:00:00 2001 From: DeborahVolpe Date: Thu, 6 Jun 2024 15:26:20 +0200 Subject: [PATCH 87/89] Documentation --- scripts/Knapsack/Knapsack.py | 2 +- scripts/linear_regression/LinearRegression.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Knapsack/Knapsack.py b/scripts/Knapsack/Knapsack.py index 3b34e57..78b7dd4 100644 --- a/scripts/Knapsack/Knapsack.py +++ b/scripts/Knapsack/Knapsack.py @@ -45,7 +45,6 @@ ] files = os.listdir("Data/") -files = ["f3_l-d_kp_4_20"] for file in files: print(file) with Path("./Data/" + file).open("r", encoding=locale.getpreferredencoding(False)) as f: @@ -102,6 +101,7 @@ ) if not isinstance(solution, bool): all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + print(all_satisfy, each_satisfy) solution.valid_solutions() solution.wring_json_reports( filename="simulated_annealing_knapsack_" + file + "_" + lambdas_m + "_" + lambdas_update, diff --git a/scripts/linear_regression/LinearRegression.py b/scripts/linear_regression/LinearRegression.py index d7c5543..46231b5 100644 --- a/scripts/linear_regression/LinearRegression.py +++ b/scripts/linear_regression/LinearRegression.py @@ -68,6 +68,7 @@ ) if not isinstance(solution, bool): all_satisfy, each_satisfy = solution.check_constraint_optimal_solution() + print(all_satisfy, each_satisfy) solution.valid_solutions() print(solution.best_energy) solution.wring_json_reports(filename="simulated_annealing_linear_regression_Iris", problem_features=True) From 254ff1ebc13b97ac92715790a2fa218c7c0b62aa Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Jun 2024 19:09:51 +0200 Subject: [PATCH 88/89] =?UTF-8?q?=F0=9F=94=A5=20remove=20requirements.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 252 ----------------------------------------------- 1 file changed, 252 deletions(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 398cf59..0000000 --- a/requirements.txt +++ /dev/null @@ -1,252 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv pip compile pyproject.toml -o requirements.txt -annotated-types==0.7.0 - # via pydantic -authlib==1.3.0 - # via dwave-cloud-client -certifi==2024.2.2 - # via requests -cffi==1.16.0 - # via cryptography -charset-normalizer==3.3.2 - # via requests -clarabel==0.8.1 - # via cvxpy -click==8.1.7 - # via dwave-cloud-client -colorama==0.4.6 - # via - # click - # pytest -contourpy==1.2.1 - # via matplotlib -cryptography==42.0.7 - # via - # authlib - # pyspnego - # requests-ntlm -cvxpy==1.5.1 - # via pyportfolioopt -cycler==0.12.1 - # via matplotlib -dill==0.3.8 - # via qiskit -dimod==0.12.14 - # via - # mqt-qao (pyproject.toml) - # dwave-networkx - # dwave-preprocessing - # dwave-samplers - # dwave-system -diskcache==5.6.3 - # via dwave-cloud-client -docplex==2.27.239 - # via - # mqt-qao (pyproject.toml) - # qiskit-optimization -dwave-cloud-client==0.11.4 - # via dwave-system -dwave-networkx==0.8.14 - # via - # dwave-system - # minorminer -dwave-preprocessing==0.6.5 - # via dwave-system -dwave-samplers==1.2.0 - # via - # mqt-qao (pyproject.toml) - # dwave-system -dwave-system==1.24.0 - # via mqt-qao (pyproject.toml) -ecos==2.0.13 - # via cvxpy -fasteners==0.19 - # via minorminer -fonttools==4.51.0 - # via matplotlib -homebase==1.0.1 - # via - # dwave-cloud-client - # dwave-system - # minorminer -idna==3.7 - # via requests -importlib-metadata==7.1.0 - # via dwave-cloud-client -iniconfig==2.0.0 - # via pytest -joblib==1.4.2 - # via scikit-learn -kiwisolver==1.4.5 - # via matplotlib -markupsafe==2.1.5 - # via werkzeug -matplotlib==3.9.0 - # via mqt-qao (pyproject.toml) -minorminer==0.2.13 - # via dwave-system -mpmath==1.3.0 - # via sympy -networkx==3.3 - # via - # dwave-networkx - # dwave-samplers - # minorminer - # qiskit-optimization -numpy==1.26.4 - # via - # mqt-qao (pyproject.toml) - # clarabel - # contourpy - # cvxpy - # dimod - # dwave-networkx - # dwave-preprocessing - # dwave-samplers - # dwave-system - # ecos - # matplotlib - # minorminer - # osqp - # pandas - # pyportfolioopt - # qdldl - # qiskit - # qiskit-algorithms - # qiskit-ibm-provider - # qiskit-optimization - # qubovert - # rustworkx - # scikit-learn - # scipy - # scs -osqp==0.6.7 - # via cvxpy -packaging==24.0 - # via - # dwave-cloud-client - # matplotlib - # pytest -pandas==2.2.2 - # via - # mqt-qao (pyproject.toml) - # pyportfolioopt -pbr==6.0.0 - # via stevedore -pillow==10.3.0 - # via matplotlib -plucky==0.4.3 - # via dwave-cloud-client -pluggy==1.5.0 - # via pytest -pycparser==2.22 - # via cffi -pydantic==2.7.1 - # via dwave-cloud-client -pydantic-core==2.18.2 - # via pydantic -pyparsing==3.1.2 - # via matplotlib -pyportfolioopt==1.5.5 - # via mqt-qao (pyproject.toml) -pysocks==1.7.1 - # via requests -pyspnego==0.10.2 - # via requests-ntlm -pytest==8.2.1 - # via mqt-qao (pyproject.toml) -python-dateutil==2.9.0.post0 - # via - # dwave-cloud-client - # matplotlib - # pandas - # qiskit - # qiskit-ibm-provider -pytz==2024.1 - # via pandas -qdldl==0.1.7.post2 - # via osqp -qiskit==1.1.0 - # via - # mqt-qao (pyproject.toml) - # qiskit-algorithms - # qiskit-ibm-provider - # qiskit-optimization -qiskit-algorithms==0.3.0 - # via qiskit-optimization -qiskit-ibm-provider==0.11.0 - # via mqt-qao (pyproject.toml) -qiskit-optimization==0.6.1 - # via mqt-qao (pyproject.toml) -qubovert==1.2.5 - # via mqt-qao (pyproject.toml) -rectangle-packer==2.0.2 - # via minorminer -requests==2.32.2 - # via - # dwave-cloud-client - # qiskit-ibm-provider - # requests-ntlm -requests-ntlm==1.2.0 - # via qiskit-ibm-provider -rustworkx==0.14.2 - # via qiskit -scikit-learn==1.5.0 - # via mqt-qao (pyproject.toml) -scipy==1.13.1 - # via - # clarabel - # cvxpy - # dwave-system - # ecos - # minorminer - # osqp - # pyportfolioopt - # qdldl - # qiskit - # qiskit-algorithms - # qiskit-optimization - # scikit-learn - # scs -scs==3.2.4.post1 - # via cvxpy -setuptools==70.0.0 - # via qiskit-optimization -six==1.16.0 - # via - # docplex - # python-dateutil -sspilib==0.1.0 - # via pyspnego -stevedore==5.2.0 - # via qiskit -symengine==0.11.0 - # via qiskit -sympy==1.12 - # via - # mqt-qao (pyproject.toml) - # qiskit -threadpoolctl==3.5.0 - # via scikit-learn -typing-extensions==4.11.0 - # via - # dwave-cloud-client - # pydantic - # pydantic-core - # qiskit - # qiskit-ibm-provider -tzdata==2024.1 - # via pandas -urllib3==2.2.1 - # via - # dwave-cloud-client - # qiskit-ibm-provider - # requests -websocket-client==1.8.0 - # via qiskit-ibm-provider -websockets==12.0 - # via qiskit-ibm-provider -werkzeug==3.0.3 - # via dwave-cloud-client -zipp==3.18.2 - # via importlib-metadata From 0bd8bbde8111c25680b08b98bf5dcae853d1dfaf Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Thu, 6 Jun 2024 19:10:18 +0200 Subject: [PATCH 89/89] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 894a621..c2fd567 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ # MQT Quantum Auto Optimizer: Automatic Framework for Solving Optimization Problems with Quantum Computers -MQT Quantum Auto Optimizer is a framework that allows one to automatically translate an optimization problem into a quantum-compliant formulation and to solve it with one of the main quantum solvers (Quantum Annealar, Quantum Approximate Optimization Algorithm, Variational Quantum Eigensolver and Grover Adaptive Search) +MQT Quantum Auto Optimizer is a framework that allows one to automatically translate an optimization problem into a quantum-compliant formulation and to solve it with one of the main quantum solvers (Quantum Annealer, Quantum Approximate Optimization Algorithm, Variational Quantum Eigensolver and Grover Adaptive Search) MQT Quantum Auto Optimizer is part of the [Munich Quantum Toolkit (MQT)](https://mqt.readthedocs.io/) developed by the [Chair for Design Automation](https://www.cda.cit.tum.de/) at the [Technical University of Munich](https://www.tum.de/). This framework has been developed in collaboration with the [VLSI Lab](https://www.vlsilab.polito.it/) of [Politecnico di Torino](https://www.polito.it).