From 01b8379b80219f64635f2a99334d9e675f692939 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:04:17 +0200 Subject: [PATCH 01/18] Added sampleset metadata extraction and quasi-profiling time measurements --- QHyper/solvers/base.py | 26 ++- .../quantum_annealing/dwave/advantage.py | 162 ++++++++++++++---- 2 files changed, 152 insertions(+), 36 deletions(-) diff --git a/QHyper/solvers/base.py b/QHyper/solvers/base.py index fc4b373..54dd01c 100644 --- a/QHyper/solvers/base.py +++ b/QHyper/solvers/base.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field import numpy as np -from typing import Any +from typing import Any, Optional from QHyper.problems.base import Problem from QHyper.optimizers import OptimizationResult @@ -20,6 +20,26 @@ class SolverConfigException(Exception): class SolverException(Exception): pass +@dataclass +class SamplesetInfo: + """ + Class for storing additional sampleset information. + Attributes + ---------- + dwave_sampleset_info : np.ndarray + Record array containing metadata obtained from D-Wave, + such as: + - qpu_access_time, + - qpu_programming_time, etc. + + time_measurements : np.ndarray + Record array containining information about time measurements of: + - accessing the clique embedding cache file, + - creating EmbeddingComposite, + - .sample() method execution, + """ + dwave_sampleset_info: np.ndarray + time_measurements: np.ndarray @dataclass class SolverResult: @@ -37,10 +57,14 @@ class SolverResult: History of the solver. Each element of the list represents the values of the objective function at each iteration - there can be multiple results per each iteration (epoch). + sampleset_info : Optional[SamplesetInfo] + Additional information about the sampleset in case of sampling-based + methods such as with quantum annealing. """ probabilities: np.recarray params: dict[Any, Any] history: list[list[OptimizationResult]] = field(default_factory=list) + sampleset_info: Optional[SamplesetInfo] = None class Solver(ABC): diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index c93099c..1cbea9d 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -1,12 +1,12 @@ import os -from typing import Any +from typing import Any, Callable, Dict import numpy as np import numpy.typing as npt from dataclasses import dataclass from collections import defaultdict from QHyper.problems.base import Problem -from QHyper.solvers.base import Solver, SolverResult +from QHyper.solvers.base import Solver, SolverResult, SamplesetInfo from QHyper.converter import Converter from QHyper.constraint import Polynomial @@ -15,8 +15,10 @@ from dimod import BinaryQuadraticModel from dwave.embedding.pegasus import find_clique_embedding +import time -DWAVE_API_TOKEN = os.environ.get('DWAVE_API_TOKEN') + +DWAVE_API_TOKEN = os.environ.get("DWAVE_API_TOKEN") @dataclass @@ -52,15 +54,18 @@ class Advantage(Solver): chain_strength: float | None = None token: str | None = None - def __init__(self, - problem: Problem, - penalty_weights: list[float] | None = None, - version: str = "Advantage_system5.4", - region: str = "eu-central-1", - num_reads: int = 1, - chain_strength: float | None = None, - use_clique_embedding: bool = False, - token: str | None = None) -> None: + def __init__( + self, + problem: Problem, + penalty_weights: list[float] | None = None, + version: str = "Advantage_system5.4", + region: str = "eu-central-1", + num_reads: int = 1, + chain_strength: float | None = None, + use_clique_embedding: bool = False, + token: str | None = None, + measure_times: bool = False, + ) -> None: self.problem = problem self.penalty_weights = penalty_weights self.version = version @@ -69,44 +74,81 @@ def __init__(self, self.chain_strength = chain_strength self.use_clique_embedding = use_clique_embedding self.sampler = DWaveSampler( - solver=self.version, region=self.region, - token=token or DWAVE_API_TOKEN) + solver=self.version, + region=self.region, + token=token or DWAVE_API_TOKEN, + ) self.token = token + self.measure_times = measure_times + self.times: Dict = {} if use_clique_embedding: - args = self.weigths if self.weigths else [] + # args = self.weigths if aself.weigths else [] + args = getattr(self, "weights", []) qubo = Converter.create_qubo(self.problem, args) qubo_terms, offset = convert_qubo_keys(qubo) bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) - self.embedding = find_clique_embedding( + find_clique_emb_handler = find_clique_embedding( bqm.to_networkx_graph(), - target_graph=self.sampler.to_networkx_graph() + target_graph=self.sampler.to_networkx_graph(), + ) + self.embedding = execute_timed( + find_clique_emb_handler, + measure_times, + self.times, + "find_clique_embedding_time", ) - def solve(self, penalty_weights: list[float] | None = None) -> Any: + def solve( + self, + penalty_weights: list[float] | None = None, + return_sampleset_info: bool = False, + ) -> Any: if penalty_weights is None and self.penalty_weights is None: - penalty_weights = [1.] * (len(self.problem.constraints) + 1) - penalty_weights = self.penalty_weights if penalty_weights is None else penalty_weights + penalty_weights = [1.0] * (len(self.problem.constraints) + 1) + penalty_weights = ( + self.penalty_weights if penalty_weights is None else penalty_weights + ) if not self.use_clique_embedding: - embedding_compose = EmbeddingComposite(self.sampler) + embedding_compose = execute_timed( + EmbeddingComposite(self.sampler), + self.measure_times, + self.times, + "embedding_composite_time", + ) else: - embedding_compose = FixedEmbeddingComposite( - self.sampler, self.embedding) + embedding_compose = execute_timed( + FixedEmbeddingComposite(self.sampler, self.embedding), + self.measure_times, + self.times, + "fixed_embedding_composite_time", + ) qubo = Converter.create_qubo(self.problem, penalty_weights) qubo_terms, offset = convert_qubo_keys(qubo) bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) - sampleset = embedding_compose.sample( - bqm, num_reads=self.num_reads, chain_strength=self.chain_strength + + # Additional sampling info + return_embedding = True + sample_func_handler = embedding_compose.sample( + bqm, + num_reads=self.num_reads, + chain_strength=self.chain_strength, + return_embedding=return_embedding, + ) + sampleset = execute_timed( + sample_func_handler, self.measure_times, self.times, "sample_time" ) result = np.recarray( (len(sampleset),), - dtype=([(v, int) for v in sampleset.variables] - + [('probability', float)] - + [('energy', float)]) + dtype=( + [(v, int) for v in sampleset.variables] + + [("probability", float)] + + [("energy", float)] + ), ) num_of_shots = sampleset.record.num_occurrences.sum() @@ -114,15 +156,27 @@ def solve(self, penalty_weights: list[float] | None = None) -> Any: for var in sampleset.variables: result[var][i] = solution.sample[var] - result['probability'][i] = ( - solution.num_occurrences / num_of_shots) - result['energy'][i] = solution.energy + result["probability"][i] = solution.num_occurrences / num_of_shots + result["energy"][i] = solution.energy - return SolverResult(result, {"penalty_weights": penalty_weights}, []) + sampleset_info = None + if return_sampleset_info: + sampleset_info = SamplesetInfo( + time_dict_to_ndarray(sampleset.info["timing"]), + time_dict_to_ndarray(self.times), + ) + + return SolverResult( + result, {"penalty_weights": penalty_weights}, [], sampleset_info + ) - def prepare_solver_result(self, result: defaultdict, arguments: npt.NDArray) -> SolverResult: - sorted_keys = sorted(result.keys(), key=lambda x: int(''.join(filter(str.isdigit, x)))) - values = ''.join(str(result[key]) for key in sorted_keys) + def prepare_solver_result( + self, result: defaultdict, arguments: npt.NDArray + ) -> SolverResult: + sorted_keys = sorted( + result.keys(), key=lambda x: int("".join(filter(str.isdigit, x))) + ) + values = "".join(str(result[key]) for key in sorted_keys) probabilities = {values: 100.0} parameters = {values: arguments} @@ -145,3 +199,41 @@ def convert_qubo_keys(qubo: Polynomial) -> tuple[dict[tuple, float], float]: new_qubo[new_key] += v return (new_qubo, offset) + + +def execute_timed( + func: Callable, measure_time: bool, times_dict: Dict, key: str +) -> Any: + """ + Execute a function with optional timing measurement. + + Parameters: + ----------- + func : callable + The function to execute and potentially time. + measure_time : bool + Whether to measure execution time. + times_dict : dict + Dictionary where timing results will be stored. + key : str + Key to use for storing the timing result. + Returns: + -------- + The result of func executed. + """ + if measure_time: + start_time = time.perf_counter() + result = func() + times_dict[key] = time.perf_counter() - start_time + return result + else: + return func() # Execute without timing overhead + + +def time_dict_to_ndarray(sampleset_info_times: dict[str, float]) -> np.ndarray: + dtype = [(key, float) for key in sampleset_info_times] + result = np.recarray((), dtype=dtype) + for key, value in sampleset_info_times.items(): + setattr(result, key, value) + + return result From 77ffb96a1b41c6b9ffe4fce1f819ea62c1150be1 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:56:20 +0200 Subject: [PATCH 02/18] Fix. Returns now full sampleset info --- QHyper/optimizers/base.py | 3 +- .../quantum_annealing/dwave/advantage.py | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/QHyper/optimizers/base.py b/QHyper/optimizers/base.py index 23af6a7..b8853e2 100644 --- a/QHyper/optimizers/base.py +++ b/QHyper/optimizers/base.py @@ -8,7 +8,8 @@ from abc import abstractmethod -from typing import Callable, Self +from typing import Callable +from typing_extensions import Self @dataclasses.dataclass diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 1cbea9d..19fce2b 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -89,12 +89,11 @@ def __init__( qubo_terms, offset = convert_qubo_keys(qubo) bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) - find_clique_emb_handler = find_clique_embedding( - bqm.to_networkx_graph(), - target_graph=self.sampler.to_networkx_graph(), - ) self.embedding = execute_timed( - find_clique_emb_handler, + lambda: find_clique_embedding( + bqm.to_networkx_graph(), + target_graph=self.sampler.to_networkx_graph(), + ), measure_times, self.times, "find_clique_embedding_time", @@ -113,14 +112,14 @@ def solve( if not self.use_clique_embedding: embedding_compose = execute_timed( - EmbeddingComposite(self.sampler), + lambda: EmbeddingComposite(self.sampler), self.measure_times, self.times, "embedding_composite_time", ) else: embedding_compose = execute_timed( - FixedEmbeddingComposite(self.sampler, self.embedding), + lambda: FixedEmbeddingComposite(self.sampler, self.embedding), self.measure_times, self.times, "fixed_embedding_composite_time", @@ -132,14 +131,16 @@ def solve( # Additional sampling info return_embedding = True - sample_func_handler = embedding_compose.sample( - bqm, - num_reads=self.num_reads, - chain_strength=self.chain_strength, - return_embedding=return_embedding, - ) sampleset = execute_timed( - sample_func_handler, self.measure_times, self.times, "sample_time" + lambda: embedding_compose.sample( + bqm, + num_reads=self.num_reads, + chain_strength=self.chain_strength, + return_embedding=return_embedding, + ), + self.measure_times, + self.times, + "sample_time", ) result = np.recarray( @@ -227,7 +228,7 @@ def execute_timed( times_dict[key] = time.perf_counter() - start_time return result else: - return func() # Execute without timing overhead + return func() def time_dict_to_ndarray(sampleset_info_times: dict[str, float]) -> np.ndarray: From 892bb7784d158f9e5da212de8ee5f12ecd6f2bc1 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:02:11 +0200 Subject: [PATCH 03/18] Small fix --- QHyper/solvers/quantum_annealing/dwave/advantage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 19fce2b..544427c 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -94,7 +94,7 @@ def __init__( bqm.to_networkx_graph(), target_graph=self.sampler.to_networkx_graph(), ), - measure_times, + self.measure_times, self.times, "find_clique_embedding_time", ) From 06c9c66bdb556235f47fe61f21fab802f8211326 Mon Sep 17 00:00:00 2001 From: Kacper Date: Thu, 12 Jun 2025 10:58:20 +0200 Subject: [PATCH 04/18] Removed default version and region in Advantage --- .../solvers/quantum_annealing/dwave/advantage.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index c93099c..51301fa 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -46,8 +46,8 @@ class Advantage(Solver): problem: Problem penalty_weights: list[float] | None = None - version: str = "Advantage_system5.4" - region: str = "eu-central-1" + version: str | None = None + region: str | None = None num_reads: int = 1 chain_strength: float | None = None token: str | None = None @@ -55,8 +55,8 @@ class Advantage(Solver): def __init__(self, problem: Problem, penalty_weights: list[float] | None = None, - version: str = "Advantage_system5.4", - region: str = "eu-central-1", + version: str | None = None, + region: str | None = None, num_reads: int = 1, chain_strength: float | None = None, use_clique_embedding: bool = False, @@ -68,9 +68,14 @@ def __init__(self, self.num_reads = num_reads self.chain_strength = chain_strength self.use_clique_embedding = use_clique_embedding - self.sampler = DWaveSampler( + if (self.version and not self.region) or (self.region and not self.version): + raise ValueError("Both 'version' and 'region' must be specified together.") + if self.version and self.region: + self.sampler = DWaveSampler( solver=self.version, region=self.region, token=token or DWAVE_API_TOKEN) + else: + self.sampler = DWaveSampler(token=token or DWAVE_API_TOKEN) self.token = token if use_clique_embedding: From 851f324e37a66469ff981269472f456feae87277 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:48:13 +0200 Subject: [PATCH 05/18] Added time units to measurements --- QHyper/solvers/base.py | 8 +- .../quantum_annealing/dwave/advantage.py | 82 +++++++++++++++---- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/QHyper/solvers/base.py b/QHyper/solvers/base.py index 54dd01c..35929d9 100644 --- a/QHyper/solvers/base.py +++ b/QHyper/solvers/base.py @@ -21,12 +21,12 @@ class SolverException(Exception): pass @dataclass -class SamplesetInfo: +class SamplesetData: """ Class for storing additional sampleset information. Attributes ---------- - dwave_sampleset_info : np.ndarray + dwave_sampleset_metadata : np.ndarray Record array containing metadata obtained from D-Wave, such as: - qpu_access_time, @@ -38,7 +38,7 @@ class SamplesetInfo: - creating EmbeddingComposite, - .sample() method execution, """ - dwave_sampleset_info: np.ndarray + dwave_sampleset_metadata: np.ndarray time_measurements: np.ndarray @dataclass @@ -64,7 +64,7 @@ class SolverResult: probabilities: np.recarray params: dict[Any, Any] history: list[list[OptimizationResult]] = field(default_factory=list) - sampleset_info: Optional[SamplesetInfo] = None + sampleset_info: Optional[SamplesetData] = None class Solver(ABC): diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 544427c..a70e38f 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -6,7 +6,7 @@ from collections import defaultdict from QHyper.problems.base import Problem -from QHyper.solvers.base import Solver, SolverResult, SamplesetInfo +from QHyper.solvers.base import Solver, SolverResult, SamplesetData from QHyper.converter import Converter from QHyper.constraint import Polynomial @@ -14,6 +14,9 @@ from dwave.system.composites import FixedEmbeddingComposite from dimod import BinaryQuadraticModel from dwave.embedding.pegasus import find_clique_embedding +import warnings + +from enum import Enum import time @@ -21,6 +24,18 @@ DWAVE_API_TOKEN = os.environ.get("DWAVE_API_TOKEN") +class TimeUnits(str, Enum): + S = "s" + US = "us" + + +class Timing: + FIND_CLIQUE_EMBEDDING = f"find_clique_embedding_time_{TimeUnits.S}" + EMBEDDING_COMPOSITE = f"embedding_composite_time_{TimeUnits.S}" + FIXED_EMBEDDING_COMPOSITE = f"fixed_embedding_composite_time_{TimeUnits.S}" + SAMPLE_FUNCTION = f"sample_time_{TimeUnits.S}" + + @dataclass class Advantage(Solver): """ @@ -64,7 +79,7 @@ def __init__( chain_strength: float | None = None, use_clique_embedding: bool = False, token: str | None = None, - measure_times: bool = False, + elapse_times: bool = False, ) -> None: self.problem = problem self.penalty_weights = penalty_weights @@ -79,11 +94,11 @@ def __init__( token=token or DWAVE_API_TOKEN, ) self.token = token - self.measure_times = measure_times + self.elapse_times = elapse_times self.times: Dict = {} if use_clique_embedding: - # args = self.weigths if aself.weigths else [] + # args = self.weigths if self.weigths else [] args = getattr(self, "weights", []) qubo = Converter.create_qubo(self.problem, args) qubo_terms, offset = convert_qubo_keys(qubo) @@ -94,15 +109,15 @@ def __init__( bqm.to_networkx_graph(), target_graph=self.sampler.to_networkx_graph(), ), - self.measure_times, + self.elapse_times, self.times, - "find_clique_embedding_time", + Timing.FIND_CLIQUE_EMBEDDING, ) def solve( self, penalty_weights: list[float] | None = None, - return_sampleset_info: bool = False, + return_sampleset_metadata: bool = False, ) -> Any: if penalty_weights is None and self.penalty_weights is None: penalty_weights = [1.0] * (len(self.problem.constraints) + 1) @@ -113,16 +128,16 @@ def solve( if not self.use_clique_embedding: embedding_compose = execute_timed( lambda: EmbeddingComposite(self.sampler), - self.measure_times, + self.elapse_times, self.times, - "embedding_composite_time", + Timing.EMBEDDING_COMPOSITE, ) else: embedding_compose = execute_timed( lambda: FixedEmbeddingComposite(self.sampler, self.embedding), - self.measure_times, + self.elapse_times, self.times, - "fixed_embedding_composite_time", + Timing.FIXED_EMBEDDING_COMPOSITE, ) qubo = Converter.create_qubo(self.problem, penalty_weights) @@ -138,9 +153,9 @@ def solve( chain_strength=self.chain_strength, return_embedding=return_embedding, ), - self.measure_times, + self.elapse_times, self.times, - "sample_time", + Timing.SAMPLE_FUNCTION, ) result = np.recarray( @@ -160,10 +175,19 @@ def solve( result["probability"][i] = solution.num_occurrences / num_of_shots result["energy"][i] = solution.energy - sampleset_info = None - if return_sampleset_info: - sampleset_info = SamplesetInfo( - time_dict_to_ndarray(sampleset.info["timing"]), + if return_sampleset_metadata and not sampleset.info["timing"]: + warnings.warn( + "No timing information available for the sampleset. ", UserWarning + ) + + sampleset_info: SamplesetData | None = None + if return_sampleset_metadata: + sampleset_info = SamplesetData( + time_dict_to_ndarray( + add_time_units_to_dwave_timing_info( + sampleset.info["timing"], TimeUnits.US + ) + ), time_dict_to_ndarray(self.times), ) @@ -238,3 +262,27 @@ def time_dict_to_ndarray(sampleset_info_times: dict[str, float]) -> np.ndarray: setattr(result, key, value) return result + + +def add_time_units_to_dwave_timing_info( + dwave_sampleset_info_timing: dict[str, float], time_unit: TimeUnits = TimeUnits.US +) -> dict[str, float]: + """ + Add time units to the D-Wave timing info. + + Parameters: + ----------- + sampleset_info_times : dict[str, float] + DWave dictionary with timing information. + time_unit : TimeUnits, optional + The time unit to append to the keys (default by DWave docs is TimeUnits.US). + + Returns: + -------- + np.ndarray + A record array with the timing information and units. + """ + dwave_keys_with_unit = [ + key + f"_{time_unit.value}" for key in dwave_sampleset_info_timing.keys() + ] + return dict(zip(dwave_keys_with_unit, dwave_sampleset_info_timing.values())) From e27fe8f7b176c425ac8c00538b229d27d69ce1e7 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Sat, 5 Jul 2025 02:01:18 +0200 Subject: [PATCH 06/18] Added heuristic embedding search with find_embedding, replaced EmbeddingComposite with FixedEmbeddingComposite in advantage.py --- .../quantum_annealing/dwave/advantage.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index a70e38f..62f1ffc 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -14,6 +14,7 @@ from dwave.system.composites import FixedEmbeddingComposite from dimod import BinaryQuadraticModel from dwave.embedding.pegasus import find_clique_embedding +from minorminer import find_embedding import warnings from enum import Enum @@ -31,9 +32,9 @@ class TimeUnits(str, Enum): class Timing: FIND_CLIQUE_EMBEDDING = f"find_clique_embedding_time_{TimeUnits.S}" - EMBEDDING_COMPOSITE = f"embedding_composite_time_{TimeUnits.S}" + FIND_HEURISTIC_EMBEDDING = f"find_heuristic_embedding_time_{TimeUnits.S}" FIXED_EMBEDDING_COMPOSITE = f"fixed_embedding_composite_time_{TimeUnits.S}" - SAMPLE_FUNCTION = f"sample_time_{TimeUnits.S}" + SAMPLE_FUNCTION = f"sample_func_time_{TimeUnits.S}" @dataclass @@ -125,24 +126,27 @@ def solve( self.penalty_weights if penalty_weights is None else penalty_weights ) + qubo = Converter.create_qubo(self.problem, penalty_weights) + qubo_terms, offset = convert_qubo_keys(qubo) + bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) + if not self.use_clique_embedding: - embedding_compose = execute_timed( - lambda: EmbeddingComposite(self.sampler), - self.elapse_times, - self.times, - Timing.EMBEDDING_COMPOSITE, - ) - else: - embedding_compose = execute_timed( - lambda: FixedEmbeddingComposite(self.sampler, self.embedding), + self.embedding = execute_timed( + lambda: find_embedding( + bqm.to_networkx_graph(), + self.sampler.to_networkx_graph(), + ), self.elapse_times, self.times, - Timing.FIXED_EMBEDDING_COMPOSITE, + Timing.FIND_HEURISTIC_EMBEDDING, ) - qubo = Converter.create_qubo(self.problem, penalty_weights) - qubo_terms, offset = convert_qubo_keys(qubo) - bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) + embedding_compose = execute_timed( + lambda: FixedEmbeddingComposite(self.sampler, self.embedding), + self.elapse_times, + self.times, + Timing.FIXED_EMBEDDING_COMPOSITE, + ) # Additional sampling info return_embedding = True From 65ee6a4d0526890e3d229e4b3f6fcdefce01bcc9 Mon Sep 17 00:00:00 2001 From: Kacper Date: Thu, 12 Jun 2025 12:31:29 +0200 Subject: [PATCH 07/18] Fixed bug with 0 --- QHyper/polynomial.py | 7 +++++++ QHyper/problems/community_detection.py | 4 ++++ QHyper/solvers/quantum_annealing/dwave/advantage.py | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/QHyper/polynomial.py b/QHyper/polynomial.py index 60befba..f0980a6 100644 --- a/QHyper/polynomial.py +++ b/QHyper/polynomial.py @@ -64,11 +64,16 @@ def __init__(self, terms: dict[tuple[str, ...], float] | float | int self.terms = defaultdict(float) + non_zero_found = False for term, coefficient in terms.items(): if coefficient == 0: continue + non_zero_found = True self.terms[tuple(sorted(term))] += coefficient + if not non_zero_found: + self.terms[tuple()] = 0.0 + @overload def __add__(self, other: float | int) -> 'Polynomial': ... @@ -204,6 +209,8 @@ def degree(self) -> int: int The degree of the polynomial. """ + if not self.terms: + return 0 return max(len(term) for term in self.terms) def get_variables(self) -> set[str]: diff --git a/QHyper/problems/community_detection.py b/QHyper/problems/community_detection.py index 29e5e4c..ed59485 100644 --- a/QHyper/problems/community_detection.py +++ b/QHyper/problems/community_detection.py @@ -164,6 +164,10 @@ def _set_objective_function(self) -> None: equation = {key: -1 * val for key, val in equation.items()} + nonzero_terms = sum(1 for v in equation.values() if not np.isclose(v, 0.0)) + if nonzero_terms == 0: + raise ValueError(f"QUBO is empty — all terms in modularity matrix are 0 or have negative values. Try lower resolution (current: {self.resolution})") + self.objective_function = Polynomial(equation) def _encode_discrete_to_one_hot( diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 51301fa..183696a 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -79,7 +79,7 @@ def __init__(self, self.token = token if use_clique_embedding: - args = self.weigths if self.weigths else [] + args = self.penalty_weights if self.penalty_weights else [] qubo = Converter.create_qubo(self.problem, args) qubo_terms, offset = convert_qubo_keys(qubo) bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) From 37501271723c880341e217a67b7216fdc212102d Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Wed, 16 Jul 2025 13:26:11 +0200 Subject: [PATCH 08/18] Review suggestions applied --- QHyper/solvers/base.py | 33 ++++++++++++++----- .../quantum_annealing/dwave/advantage.py | 11 ++++--- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/QHyper/solvers/base.py b/QHyper/solvers/base.py index 35929d9..3e466b9 100644 --- a/QHyper/solvers/base.py +++ b/QHyper/solvers/base.py @@ -27,16 +27,33 @@ class SamplesetData: Attributes ---------- dwave_sampleset_metadata : np.ndarray - Record array containing metadata obtained from D-Wave, - such as: - - qpu_access_time, - - qpu_programming_time, etc. + Record array containing metadata obtained from D-Wave: + - qpu_sampling_time_us, + - qpu_anneal_time_per_sample_us, + - qpu_readout_time_per_sample_us, + - qpu_access_time_us, + - qpu_access_overhead_time_us, + - qpu_programming_time_us, + - qpu_delay_time_per_sample_us, + - total_post_processing_time_us, + - post_processing_overhead_time_us, + + The time units are microseconds (us) according to the D-Wave Docs (July 2025): + https://docs.dwavequantum.com/en/latest/quantum_research/operation_timing.html. + time_measurements : np.ndarray Record array containining information about time measurements of: - - accessing the clique embedding cache file, - - creating EmbeddingComposite, - - .sample() method execution, + - find_clique_embedding_time_s - in case of clique embedding: + first call to that function after installment results + in the embedding search (might take minutes), next calls are accessing the clique + emedding cache file, + or + - find_heuristic_embedding_time_s - in case of heuristic embedding: search for heuristic embedding, + - fixed_embedding_composite_time_s - creating FixedEmbeddingComposite object, + - sample_func_time_s - method execution of the .sample function - communication with the solver itself. + (https://dwave-systemdocs.readthedocs.io/en/link_fix/reference/composites/generated/dwave.system.composites.FixedEmbeddingComposite.sample.html#dwave.system.composites.FixedEmbeddingComposite.sample), + """ dwave_sampleset_metadata: np.ndarray time_measurements: np.ndarray @@ -57,7 +74,7 @@ class SolverResult: History of the solver. Each element of the list represents the values of the objective function at each iteration - there can be multiple results per each iteration (epoch). - sampleset_info : Optional[SamplesetInfo] + sampleset_info : Optional[SamplesetData] Additional information about the sampleset in case of sampling-based methods such as with quantum annealing. """ diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 8f0ef95..1b81e07 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -106,7 +106,7 @@ def __init__(self, def solve( self, penalty_weights: list[float] | None = None, - return_sampleset_metadata: bool = False, + return_metadata: bool = False, ) -> Any: if penalty_weights is None and self.penalty_weights is None: penalty_weights = [1.0] * (len(self.problem.constraints) + 1) @@ -167,13 +167,12 @@ def solve( result["probability"][i] = solution.num_occurrences / num_of_shots result["energy"][i] = solution.energy - if return_sampleset_metadata and not sampleset.info["timing"]: + if return_metadata and not sampleset.info["timing"]: warnings.warn( "No timing information available for the sampleset. ", UserWarning ) - sampleset_info: SamplesetData | None = None - if return_sampleset_metadata: + if return_metadata: sampleset_info = SamplesetData( time_dict_to_ndarray( add_time_units_to_dwave_timing_info( @@ -182,6 +181,8 @@ def solve( ), time_dict_to_ndarray(self.times), ) + else: + sampleset_info = None return SolverResult( result, {"penalty_weights": penalty_weights}, [], sampleset_info @@ -264,7 +265,7 @@ def add_time_units_to_dwave_timing_info( Parameters: ----------- - sampleset_info_times : dict[str, float] + dwave_sampleset_info_timing : dict[str, float] DWave dictionary with timing information. time_unit : TimeUnits, optional The time unit to append to the keys (default by DWave docs is TimeUnits.US). From 397b3a99567b614ed982556699294f9e3a51b310 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:28:46 +0200 Subject: [PATCH 09/18] Fix in .sample() future-like object resolving --- .../quantum_annealing/dwave/advantage.py | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 1b81e07..c5914c1 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -10,7 +10,7 @@ from QHyper.converter import Converter from QHyper.constraint import Polynomial -from dwave.system import DWaveSampler, EmbeddingComposite +from dwave.system import DWaveSampler from dwave.system.composites import FixedEmbeddingComposite from dimod import BinaryQuadraticModel from dwave.embedding.pegasus import find_clique_embedding @@ -20,6 +20,7 @@ from enum import Enum import time +import dimod DWAVE_API_TOKEN = os.environ.get("DWAVE_API_TOKEN") @@ -57,7 +58,7 @@ class Advantage(Solver): use_clique_embedding: bool, default False Find clique for the embedding **config: Any - Config for the D-Wave solver. Documentation available at https://docs.dwavequantum.com + Config for the D-Wave solver. Documentation available at https://docs.dwavequantum.com """ problem: Problem @@ -66,22 +67,23 @@ class Advantage(Solver): chain_strength: float | None = None token: str | None = None - def __init__(self, - problem: Problem, - penalty_weights: list[float] | None = None, - num_reads: int = 1, - chain_strength: float | None = None, - use_clique_embedding: bool = False, - token: str | None = None, - elapse_times: bool = False, - **config: Any) -> None: + def __init__( + self, + problem: Problem, + penalty_weights: list[float] | None = None, + num_reads: int = 1, + chain_strength: float | None = None, + use_clique_embedding: bool = False, + token: str | None = None, + elapse_times: bool = False, + **config: Any, + ) -> None: self.problem = problem self.penalty_weights = penalty_weights self.num_reads = num_reads self.chain_strength = chain_strength self.use_clique_embedding = use_clique_embedding - self.sampler = DWaveSampler( - token=token or DWAVE_API_TOKEN, **config) + self.sampler = DWaveSampler(token=token or DWAVE_API_TOKEN, **config) self.token = token self.elapse_times = elapse_times self.times: Dict = {} @@ -138,12 +140,22 @@ def solve( # Additional sampling info return_embedding = True - sampleset = execute_timed( - lambda: embedding_compose.sample( - bqm, - num_reads=self.num_reads, - chain_strength=self.chain_strength, - return_embedding=return_embedding, + + # Resolving from the sampleset future-like object + def _resolve_future_and_return( + sampleset: dimod.sampleset.SampleSet, + ) -> dimod.sampleset.SampleSet: + sampleset.resolve() + return sampleset + + sampleset: dimod.sampleset.SampleSet = execute_timed( + lambda: _resolve_future_and_return( + embedding_compose.sample( + bqm, + num_reads=self.num_reads, + chain_strength=self.chain_strength, + return_embedding=return_embedding, + ) ), self.elapse_times, self.times, From 51e10fbcc4b93d3bfc907e58bd45573097342a02 Mon Sep 17 00:00:00 2001 From: basiav <82549088+basiav@users.noreply.github.com> Date: Mon, 21 Jul 2025 12:15:43 +0200 Subject: [PATCH 10/18] Made the fix in .sample() future-like resolving simpler --- .../quantum_annealing/dwave/advantage.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index c5914c1..8d3f1d5 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -141,26 +141,18 @@ def solve( # Additional sampling info return_embedding = True - # Resolving from the sampleset future-like object - def _resolve_future_and_return( - sampleset: dimod.sampleset.SampleSet, - ) -> dimod.sampleset.SampleSet: - sampleset.resolve() - return sampleset - - sampleset: dimod.sampleset.SampleSet = execute_timed( - lambda: _resolve_future_and_return( - embedding_compose.sample( + start = time.perf_counter() + sampleset = embedding_compose.sample( bqm, num_reads=self.num_reads, chain_strength=self.chain_strength, return_embedding=return_embedding, - ) - ), - self.elapse_times, - self.times, - Timing.SAMPLE_FUNCTION, - ) + ) + # Resolving from the sampleset future-like object + sampleset.resolve() + end = time.perf_counter() + if self.elapse_times: + self.times[Timing.SAMPLE_FUNCTION] = end - start result = np.recarray( (len(sampleset),), From 02e340305cfaeb4be041ba8e80f2a36177ee50dd Mon Sep 17 00:00:00 2001 From: Kacper Date: Tue, 15 Jul 2025 09:19:04 +0200 Subject: [PATCH 11/18] Full modularity matrix will calculate only once --- QHyper/problems/community_detection.py | 25 +++++++++++-------------- requirements/prod.txt | 1 + 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/QHyper/problems/community_detection.py b/QHyper/problems/community_detection.py index ed59485..327e014 100644 --- a/QHyper/problems/community_detection.py +++ b/QHyper/problems/community_detection.py @@ -22,34 +22,31 @@ class Network: resolution: float = 1.0 weight: str | None = "weight" community: list | None = None - full_modularity_matrix: np.ndarray = field(init=False) + full_modularity_matrix: np.ndarray | None = None generalized_modularity_matrix: np.ndarray = field(init=False) def __post_init__(self) -> None: if not self.community: self.community = [*range(self.graph.number_of_nodes())] - ( - self.full_modularity_matrix, - self.generalized_modularity_matrix, - ) = self.calculate_modularity_matrix() + if self.full_modularity_matrix is None: + self.full_modularity_matrix = self.calculate_full_modularity_matrix() + self.generalized_modularity_matrix = self.calculate_generalized_modularity_matrix() + - def calculate_modularity_matrix(self) -> np.ndarray: + def calculate_full_modularity_matrix(self) -> np.ndarray: adj_matrix: np.ndarray = nx.to_numpy_array(self.graph, weight=self.weight) in_degree_matrix: np.ndarray = adj_matrix.sum(axis=1) out_degree_matrix: np.ndarray = adj_matrix.sum(axis=0) m: int = np.sum(adj_matrix) - full_modularity_matrix = ( - adj_matrix - - self.resolution * np.outer(in_degree_matrix, out_degree_matrix) / m - ) - - B_bis = full_modularity_matrix[self.community, :] + return adj_matrix - self.resolution * np.outer(in_degree_matrix, out_degree_matrix) / m + + def calculate_generalized_modularity_matrix(self) -> np.ndarray: + B_bis = self.full_modularity_matrix[self.community, :] B_community = B_bis[:, self.community] B_i = np.sum(B_community, axis=1) B_j = np.sum(B_community.T, axis=1) delta = np.eye(len(self.community), dtype=np.int32) - B_g = 0.5*( B_community + B_community.T ) - 0.5 * delta * (B_i + B_j) - return full_modularity_matrix, B_g + return 0.5 * (B_community + B_community.T) - 0.5 * delta * (B_i + B_j) class KarateClubNetwork(Network): diff --git a/requirements/prod.txt b/requirements/prod.txt index 8feee23..ad58b1b 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -6,4 +6,5 @@ dwave-system gurobipy types-tqdm pandas +autoray==0.6.11 git+https://github.com/wfcommons/wfcommons.git@main From dc91e36c4be6f41f797d1e78575451a1ae1037cb Mon Sep 17 00:00:00 2001 From: Kacper Date: Sun, 2 Nov 2025 20:30:19 +0100 Subject: [PATCH 12/18] Changed error value and applied Black formatter --- QHyper/problems/community_detection.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/QHyper/problems/community_detection.py b/QHyper/problems/community_detection.py index 327e014..9247d94 100644 --- a/QHyper/problems/community_detection.py +++ b/QHyper/problems/community_detection.py @@ -30,16 +30,20 @@ def __post_init__(self) -> None: self.community = [*range(self.graph.number_of_nodes())] if self.full_modularity_matrix is None: self.full_modularity_matrix = self.calculate_full_modularity_matrix() - self.generalized_modularity_matrix = self.calculate_generalized_modularity_matrix() - + self.generalized_modularity_matrix = ( + self.calculate_generalized_modularity_matrix() + ) def calculate_full_modularity_matrix(self) -> np.ndarray: adj_matrix: np.ndarray = nx.to_numpy_array(self.graph, weight=self.weight) in_degree_matrix: np.ndarray = adj_matrix.sum(axis=1) out_degree_matrix: np.ndarray = adj_matrix.sum(axis=0) m: int = np.sum(adj_matrix) - return adj_matrix - self.resolution * np.outer(in_degree_matrix, out_degree_matrix) / m - + return ( + adj_matrix + - self.resolution * np.outer(in_degree_matrix, out_degree_matrix) / m + ) + def calculate_generalized_modularity_matrix(self) -> np.ndarray: B_bis = self.full_modularity_matrix[self.community, :] B_community = B_bis[:, self.community] @@ -128,9 +132,9 @@ def __init__( self._set_objective_function() self._set_one_hot_constraints(communities) else: - self.variables: tuple[ - sympy.Symbol - ] = self._get_discrete_variable_representation() + self.variables: tuple[sympy.Symbol] = ( + self._get_discrete_variable_representation() + ) self._set_objective_function() def _get_discrete_variable_representation( @@ -163,7 +167,9 @@ def _set_objective_function(self) -> None: nonzero_terms = sum(1 for v in equation.values() if not np.isclose(v, 0.0)) if nonzero_terms == 0: - raise ValueError(f"QUBO is empty — all terms in modularity matrix are 0 or have negative values. Try lower resolution (current: {self.resolution})") + raise ValueError( + f"The objective function is a zero polynomial - all terms in the generalized modularity matrix are 0. Try different resolution (current: {self.resolution})" + ) self.objective_function = Polynomial(equation) From 38c81f67571c56fbcbaf2d150d945f12008ecce5 Mon Sep 17 00:00:00 2001 From: Barbara Wojtarowicz Date: Tue, 11 Nov 2025 18:40:41 +0100 Subject: [PATCH 13/18] Updates --- .../quantum_annealing/dwave/advantage.py | 76 ++- id_2_sampleset_adv.npy | Bin 0 -> 3917 bytes id_2_sampleset_adv.pkl | Bin 0 -> 3789 bytes id_2_sampleset_adv_serializable.pkl | Bin 0 -> 2092 bytes id_3_sampleset_adv.npy | Bin 0 -> 3981 bytes id_3_sampleset_adv.pkl | Bin 0 -> 3853 bytes id_3_sampleset_adv_serializable.pkl | Bin 0 -> 2136 bytes sampleset_adv.npy | Bin 0 -> 3011 bytes sampleset_adv.pkl | Bin 0 -> 2883 bytes sampleset_adv_serializable.pkl | Bin 0 -> 1169 bytes t.ipynb | 595 ++++++++++++++++++ 11 files changed, 661 insertions(+), 10 deletions(-) create mode 100644 id_2_sampleset_adv.npy create mode 100644 id_2_sampleset_adv.pkl create mode 100644 id_2_sampleset_adv_serializable.pkl create mode 100644 id_3_sampleset_adv.npy create mode 100644 id_3_sampleset_adv.pkl create mode 100644 id_3_sampleset_adv_serializable.pkl create mode 100644 sampleset_adv.npy create mode 100644 sampleset_adv.pkl create mode 100644 sampleset_adv_serializable.pkl create mode 100644 t.ipynb diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index 8d3f1d5..c1f5de8 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -15,7 +15,11 @@ from dimod import BinaryQuadraticModel from dwave.embedding.pegasus import find_clique_embedding from minorminer import find_embedding +from dwave.system import LeapHybridBQMSampler import warnings +import pickle +import dwave.inspector +from dwave.inspector.adapters import enable_data_capture from enum import Enum @@ -105,10 +109,13 @@ def __init__( Timing.FIND_CLIQUE_EMBEDDING, ) + enable_data_capture() + def solve( self, penalty_weights: list[float] | None = None, return_metadata: bool = False, + saving_path: str | None = None, ) -> Any: if penalty_weights is None and self.penalty_weights is None: penalty_weights = [1.0] * (len(self.problem.constraints) + 1) @@ -148,12 +155,50 @@ def solve( chain_strength=self.chain_strength, return_embedding=return_embedding, ) + # bqm = dimod.BQM.from_qubo(qubo_terms, offset=offset) + # sampleset = dimod.ExactSolver().sample(bqm) # Resolving from the sampleset future-like object sampleset.resolve() - end = time.perf_counter() + end = time.perf_counter() if self.elapse_times: self.times[Timing.SAMPLE_FUNCTION] = end - start + arr_to_save = np.array(sampleset, dtype=object) + + # try: + # dwave.inspector.show(sampleset) + # except Exception as e: + # print(f"Could not open DWave Inspector: {e}") + + try: + with open(f"{saving_path}.pkl" if saving_path else "sampleset_adv.pkl", "wb") as f: + pickle.dump(arr_to_save, f) + except Exception as e: + print(f"Could not save sampleset to .pkl file: {e}") + + + try: + pickle_bytes = pickle.dumps(sampleset.to_serializable()) + with open(f"{saving_path}_serializable.pkl" if saving_path else "sampleset_adv_serializable.pkl", "wb") as f: + f.write(pickle_bytes) + except Exception as e: + print(f"Could not save serializable sampleset to .pkl file: {e}") + + try: + pickle.dumps(sampleset) + except Exception as e: + print(f"Could not pickle sampleset object: {e}") + + try: + np.save(f"{saving_path}.npy" if saving_path else "sampleset_adv.npy", arr_to_save) + except Exception as e: + print(f"Could not save times to .npy file: {e}") + + try: + sampleset.to_file(f"{saving_path}.json" if saving_path else "sampleset_adv.json", cls='json') + except Exception as e: + print(f"Could not save sampleset to .json file: {e}") + result = np.recarray( (len(sampleset),), dtype=( @@ -171,20 +216,25 @@ def solve( result["probability"][i] = solution.num_occurrences / num_of_shots result["energy"][i] = solution.energy - if return_metadata and not sampleset.info["timing"]: + if return_metadata or not "timing" in sampleset.info or not sampleset.info["timing"]: warnings.warn( "No timing information available for the sampleset. ", UserWarning ) if return_metadata: - sampleset_info = SamplesetData( - time_dict_to_ndarray( - add_time_units_to_dwave_timing_info( - sampleset.info["timing"], TimeUnits.US - ) - ), - time_dict_to_ndarray(self.times), - ) + if "timing" in sampleset.info and sampleset.info["timing"]: + sampleset_info = SamplesetData( + time_dict_to_ndarray( + add_time_units_to_dwave_timing_info( + sampleset.info["timing"], TimeUnits.US + ) + ), + time_dict_to_ndarray(self.times), + ) + else: + sampleset_info = SamplesetData( + None, time_dict_to_ndarray(self.times) + ) else: sampleset_info = None @@ -283,3 +333,9 @@ def add_time_units_to_dwave_timing_info( key + f"_{time_unit.value}" for key in dwave_sampleset_info_timing.keys() ] return dict(zip(dwave_keys_with_unit, dwave_sampleset_info_timing.values())) + + +def __str__(self) -> str: + G = self.problem.network_data.graph + n = G.number_of_nodes() + diff --git a/id_2_sampleset_adv.npy b/id_2_sampleset_adv.npy new file mode 100644 index 0000000000000000000000000000000000000000..8c997de1fc0d4de6aefd5e10553e470a0c1fb1b4 GIT binary patch literal 3917 zcmbtXO>A7Z5#H7RUoG2lj8;vJMUzG{ULIrl&B4ee1$rpZqXXm+x-0IAbZ+9uhmn07m zIr?TeoZ$?Ivxm8Aw(xQ~wUc^f(P5z-EdC<1cqhMjA+y-wO zT?YRzoxhN|oB4j<%pbAHMfmgEvipXZ}u+=+T!hVmo%b@}ESnl&oYcVsS?yYUD< zHIU6n*5BNcV%~8(zOxe2PPffM7D+K(R&*KYLwWvHc~>rpNo7soNIoK_waH+f6jLyo z*6_*17BaFg`79VTfo{OU!=W*JKDQ($^o~+YFpmXI@OU2dTE1<^LBKqlg;JccIdwg& z9x!^#Y6R4dT;G!sTEw5`vtqQideKx1(1^QgB1e5rfzM=SUmn0&kQtID3P>GD{tPZ{ z967LG9y>6-7-WB@wlQS+)yHge8YG|PSIEMFjLA=7uakJ-*Ir2Dm%_jQV=x|l^^dep zh19$6;P<~xC80#R54N9ru>IG~qY|HO!V%QPjI~1pm)0R_Qk>FJw0j1&U|HSXo)vpt z*S^(emffoj7C?R^fj1URoBSK^(|dC{6-_v9k`g0(7bQu+V=%2r zG7i(vC7FQfiX@XTU6o`CrgcfCVcL)}1};ldJV(+zPeyowjPfEG<0UfA%VdIA$Rw|l zDPAMfF`2om{2aGjui>jKoQT|x>opa9YP%a-Du)2EfWhST=lu5?_=yE%QqNwi0Q`=OXu%52EUu)oj0e?x)yiuj?y@^@IkL0Mns zHTU!Vb03t%8I(_@f6({g06Eur}>I#)dU{`yuQk79u|aU%Gx6p)Rz= zP<8X4x|sarIRCg!iC`>dKnY|{$8sGho}sI(adrKovwV5|^2Oyfn>CgPUAw#iImSA5<~X=76sCynsf#G42e1?i&Mw_yD+6Q&i)jc&wSzhOYqg#^WmVJS z0Lv8A7fgx2XYb6yg~^c*vwuV)PyUpB7l{J-bM`Mt6v=)DD3dR;|3#ug z9%Vm8qDuC%Um{T>uV+W+;O1fNnzM8nVNMgSib}yPD4isIASurc$^4Kk49Vh zkgN>J>X57r$XJ|)431b*zASBqn6>?Oo2iNhXEW=t28HVHxVqR+)ngal0uNYYZ8yY9 zypKhmS9$F~ZsCPQ4@jEv8n5;dC}@aOd47N}p6~O4i@butD;(j~j;%{}QtN8R)|tHg zkeAq0Ff?hK^1O)qk`(1d%_M0Gww3y5$wbS2v}~f4K3W-~1yiqb4fPgGy#{LNHBdwE z0L}6o?q-~Gj%WKwa?aVr4DczhnYedWp9XqbFj2#QrAW&f{u`)ar-2%F8mNjs?p8H- zQ}IExHbir#y~;hbA!piapoYB$YS?R_hP?)A*lVDMy#{L7J3xy%ibf1dI@*XNF(`6l zZ*4O8ROH6q25RhWpvK+szT~s@;RV z%lhW)m=4g2DXX0Z*@`LKM`JOcR6=Mfnb(ZCyuP_`<&)2!y0#qG#c8wI>ad9W@HG6O zLtB2}Mm=lCj~H}hgVJtwDLiNl>KfKmaYClwUEXT2%3*ek{UX z7_rXEKuDaqhFu>#63WJ#dNCA0G1-Aj+3o|re8L+_j znk>jfoO&>@Ow-+AUPjr6T8D~ zsc$xnnuc-<$Ov5lU_`6bBLE{xR+VH`Nmeo40D-K~wE;$ySH&Mjl&>lInv$<6 z`C1|miO#|pg4ntVO=;`5Fo;tsUe9BbJ`7gtcgVW%lE2HsXj!-TndC=C2HOV+afW8< zfq$zX9NF4}HDsyvdzdg!PDV6nvdHLj`L;Nj1Zmi}Zb9Eb#hg|S!E@Liyfg98%6p(s z+0%LpsiV8JBw##f-G>P@!S za_GB`oMxCD=eguKV-|}kJW74}PUs&D$^X!1OhWUY{B%^M=$>jg#96BmN6@NSyVQ-K TTZDc&gg!-b9@i=S3|aXam42cY literal 0 HcmV?d00001 diff --git a/id_2_sampleset_adv.pkl b/id_2_sampleset_adv.pkl new file mode 100644 index 0000000000000000000000000000000000000000..38159ad3e4d4eb5c3c00454e83138b97b978b685 GIT binary patch literal 3789 zcmbVPO>A355VrIGN7I&oAV6jDr&c0S(}XsWkOCA`)W!clMMB|e?YH(m*M84=KS>O& z1VRZ^?4@)IqIVETh!Y2HAUIT9K;nSJu}B(fo|N6mH?y-dJF~On zH%G32dnlnkalae2JKaUA=J{-~9koJ-`abPSF=P3x=D9)WN3~F1lVVg!N-^%*TI8A} ziCuX%S(Wd|f;>)=C-|@!wZm?Qq5M#GRbF{lvxY_TlFVc>=kLI$2C^Q?>Xi*CW^JeK z*^2>fcUml9p%jxvMHhj-CQrO2FU#X%Tv_AWk`IYVZ8DfA#RQC|HGDj_g$(UVJ`Dzq zp&PL9+Q1k-n>jAV^o~-DF_-xb@OT#VT3)Rd`95=NERbTZ#;N04RiDv|R^6wy(D7Uu zqDA~MJ}rhTOD9dW01Y`yCbHk>1o%v*cI6(N1(_mAqJYGnmJ#UT5H z+QyLOXYR7iQILF+pCtFGLgL0p`2Di3B$PD8HxiY6R4Nr<7HlaeH1T9RZ4rc;s(!?Y~P2uv%IjKcJ^Bx5k0mSh~J zGm=cev?|FYOlva2z@(xVV)-=yg){Ik&N*Y8Rum(!7F4kB2$-@pQD!J z);*PlW1-V_+=il$Y<40`bi`!6wB%`UkjtuN__VoLMg~C z+l#`xh?Ugk2G6?Ur5?6swpe}+V!{FMF*i2}KmzKKMU{E_|{i4wV!{tbyT*-8J2M1{PQ z9-e`lhqY_Q(q)9%4Y(>Q1vj8{lH{JGJToA(12Q)t^8>OlAd3UCG$6|ZveG9baTGE* zWO4bjv>9T$=CxW(RWvx8X`9t4RDavi#eSk1Iq(*^z#3^e0aoH&Eb_d}D|>PSFC=vqNm8(_&_fF*TI``k6D{@7(g4kwdX;OaH)rZKP(!bQ8hZO^nrCn~+M(9@iW8vZLqTGsI2Kn*($)UeY)RrGPUvbmdz52BR;nlbHF?x77C z(_RBL>@`rsUIR7kHBiG|12yb5P{ZCnn%7Y@Vo=c0MkJ0wo*R2>lfkDvH}*DAV{ZdB z_U@wvQ?GU!^cGCL25RUvP(yDYEou#hPbIyR;ZsrHN*z<}9_(GzH($rJkCseX?KH@i zOxYe9iP^XkLQ~1yM#$y4_4(7k-hTM(LR1w;&1S33LhixSa8H{yJ>Lnt)|MAC=*aq| z-Re+y&=}M;tf}IVUVRtMVq%;6F1#86-X|!(Vnns5;y(RY1l=HH?Zv*3m^+JIA3PGu z#tV8e6hJZFhG&m9z>H^$UYn&hBWn9JbZV)pLjxA1sLxVhf#)`up9(p3VPL6-v&Gz$ zvJbi1b1~XtTdXC?F)?D(kfIOw243XXm|3lr&2UBFzUey-Bjl&P*)VDv$}OZE%H$QI zDjd*IO(10uFDP8qIG{BSxduT+Zc%YntpgglMND)UA#Wg_C$L^5~ondQCiuh#E+a#0_3{WO^D0#^kPm537bFN zmd~Bm=5M+2FA`8gk#Z*>9SBl^JK&{ZL*USq117CBH05B);dwc%$>F>lFhix`h5$Z4 zj-xYv>BW~XUU>zp<44^%PZsk-Kk6xaai^a-Dz!M{paVqfLi|}*K72_!NfZGIl*{Qu zl7l76%8wg=TB0xqUYxNuTug6Ttn>W~1bwgbCl9$|Jf;+b6_~gE z`!|>GUg2el=_he7A)!=X_`myhUxj~4`aKB9=n)z$apM42;!7-MxR-vMG8s#1ITY&J z*J?-nnTP!kYtq1spTZ#6C86Vcfb>oP^kf}n5k zf3WYO*^uUey^m&7n!npWqG?F;f&D9*rZk84A81f(u)52$h|TcnM*?Tj}^Dg|tEv zsNmvp)PtnLD2Z@@O3xoaR8i8THl3&y$!m7l~PO%U8Uzh zzN_Q+s`{?!?;0(>t7^Wk=j(dDPK)`P@;9` zR(6FiFp~7}2UpyOs;+q-;r}l$`(YnlC45f*WcZuP7THOI+B%CrbQk2 I46>~DH{<6RV*mgE literal 0 HcmV?d00001 diff --git a/id_3_sampleset_adv.npy b/id_3_sampleset_adv.npy new file mode 100644 index 0000000000000000000000000000000000000000..c8a2a5f2a8b64e52e3bc0f2a79ea6bb7fe788563 GIT binary patch literal 3981 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 Su@#SHFp()#&5=TyR{jBL;38)L literal 0 HcmV?d00001 diff --git a/sampleset_adv.npy b/sampleset_adv.npy new file mode 100644 index 0000000000000000000000000000000000000000..d34107685d2149625b15583759e9dd68b0c7c496 GIT binary patch literal 3011 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 MxzHpoav0|R0wVvseE5 percent chain breaks is 100.0.\n" + ] + } + ], + "source": [ + "sampleset = ls\n", + "print(\"Number of nodes in one set is {}, in the other, {}. \\nEnergy is {}.\".format(\n", + " sum(sampleset.first.sample.values()),\n", + " 10 - sum(sampleset.first.sample.values()),\n", + " sampleset.first.energy)) \n", + "print(\"Percentage of samples with >5 percent chain breaks is {}.\".format(\n", + " np.count_nonzero(sampleset.record.chain_break_fraction > 0.05)/2*100)) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "484eb225", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[1, 0, 0, 0, 1, 0, 1, 1, 0, 0],\n", + " [0, 1, 0, 1, 0, 0, 0, 1, 1, 0]], dtype=int8),\n", + " ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9'])" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# import dimod\n", + "\n", + "\n", + "# dimod.as_samples(ls)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9a3218a1", + "metadata": {}, + "outputs": [], + "source": [ + "def communities_to_list(sample, communities_number) -> list:\n", + " communities = []\n", + " for k in range(communities_number):\n", + " subcommunity = []\n", + " for i in sample:\n", + " if sample[i] == k:\n", + " key = int(i[1:])\n", + " subcommunity.append(key)\n", + " communities.append(subcommunity)\n", + "\n", + " return communities" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ed4abea0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[2, 3, 9], [0, 1, 4, 5, 6, 7, 8]]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "communities_to_list(ls.first.sample, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1dff148f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.12345679012345673" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nx.community.modularity(G, communities_to_list(ls.first.sample, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "59eeb339", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0001" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ls.info[\"embedding_context\"][\"chain_strength\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "a1514ae6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.5, 0.4])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ls.record.chain_break_fraction" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "3e6e48c0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Percentage of samples with high rates of breaks is 100.0.\n" + ] + } + ], + "source": [ + "sampleset = ls\n", + "print(\"Percentage of samples with high rates of breaks is {}.\".format(\n", + " np.count_nonzero(sampleset.record.chain_break_fraction > 0.33)/2*100)) " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "24a3a992", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'29722194-e555-4b1f-9f80-7b98a4c8fef3'" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "problem_id = ls.info[\"problem_id\"]\n", + "problem_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0733df06", + "metadata": {}, + "outputs": [], + "source": [ + "from dwave.inspector import storage\n", + "\n", + "# try:\n", + "# pd = storage.get_problem(problem_id)\n", + "# except KeyError:\n", + "# pd = None\n", + "# pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb9e7da2", + "metadata": {}, + "outputs": [], + "source": [ + "pd = storage.get_problem(problem_id)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d37c2957", + "metadata": {}, + "outputs": [], + "source": [ + "# from dwave.inspector.adapters import enable_data_capture\n", + "\n", + "# enable_data_capture()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "a286283c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SampleSet(rec.array([([1, 0, 1, 1, 1, 1, 0, 1, 1, 1], -0.61111111, 1, 0.5),\n", + " ([1, 1, 0, 0, 1, 1, 1, 1, 1, 0], -1.11111111, 1, 0.4)],\n", + " dtype=[('sample', 'i1', (10,)), ('energy', ', 'message': 'Some quadratic biases are stronger than the given chain strength', 'level': 30, 'data': {'source_interactions': [['x1', 'x0'], ['x2', 'x0'], ['x2', 'x1'], ['x3', 'x0'], ['x3', 'x1'], ['x3', 'x2'], ['x4', 'x0'], ['x4', 'x1'], ['x4', 'x2'], ['x4', 'x3'], ['x5', 'x0'], ['x5', 'x1'], ['x5', 'x2'], ['x5', 'x3'], ['x5', 'x4'], ['x6', 'x0'], ['x6', 'x1'], ['x6', 'x2'], ['x6', 'x3'], ['x6', 'x4'], ['x6', 'x5'], ['x7', 'x0'], ['x7', 'x1'], ['x7', 'x2'], ['x7', 'x3'], ['x7', 'x4'], ['x7', 'x5'], ['x7', 'x6'], ['x8', 'x0'], ['x8', 'x1'], ['x8', 'x2'], ['x8', 'x3'], ['x8', 'x4'], ['x8', 'x5'], ['x8', 'x6'], ['x8', 'x7'], ['x9', 'x0'], ['x9', 'x1'], ['x9', 'x2'], ['x9', 'x3'], ['x9', 'x4'], ['x9', 'x5'], ['x9', 'x6'], ['x9', 'x7'], ['x9', 'x8']]}}, {'type': , 'message': 'Lowest-energy samples contain a broken chain', 'level': 40, 'data': {'target_variables': [165, 2985], 'source_variables': ['x3'], 'sample_index': 0}}, {'type': , 'message': 'Lowest-energy samples contain a broken chain', 'level': 40, 'data': {'target_variables': [225, 3015], 'source_variables': ['x5'], 'sample_index': 0}}, {'type': , 'message': 'Lowest-energy samples contain a broken chain', 'level': 40, 'data': {'target_variables': [255, 3045], 'source_variables': ['x7'], 'sample_index': 0}}, {'type': , 'message': 'Lowest-energy samples contain a broken chain', 'level': 40, 'data': {'target_variables': [120, 3060], 'source_variables': ['x8'], 'sample_index': 0}}, {'type': , 'message': 'Lowest-energy samples contain a broken chain', 'level': 40, 'data': {'target_variables': [135, 3075], 'source_variables': ['x9'], 'sample_index': 0}}, {'type': , 'message': 'All samples have broken chains', 'level': 30, 'data': {}}]}, 'BINARY')" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ls" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "c09d5e09", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "Serving Inspector on http://127.0.0.1:18000/?problemId=29722194-e555-4b1f-9f80-7b98a4c8fef3" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "'http://127.0.0.1:18000/?problemId=29722194-e555-4b1f-9f80-7b98a4c8fef3'" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import dwave.inspector\n", + "from dwave.inspector import show\n", + "\n", + "show(ls)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "15145b52", + "metadata": {}, + "outputs": [], + "source": [ + "from dwave.system import DWaveSampler\n", + "from dwave.system.composites import FixedEmbeddingComposite\n", + "\n", + "\n", + "version = \"Advantage_system4.1\"\n", + "region = \"na-west-1\"\n", + "\n", + "sampler = DWaveSampler(solver=version, region=region)\n", + "fixed_embedding_composite = FixedEmbeddingComposite(sampler, embedding=ls.info[\"embedding_context\"][\"embedding\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "0c843628", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_embedding_composite.warnings_default" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "b8c7ced3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': dwave.system.warnings.ChainStrengthWarning,\n", + " 'message': 'Some quadratic biases are stronger than the given chain strength',\n", + " 'level': 30,\n", + " 'data': {'source_interactions': [['x1', 'x0'],\n", + " ['x2', 'x0'],\n", + " ['x2', 'x1'],\n", + " ['x3', 'x0'],\n", + " ['x3', 'x1'],\n", + " ['x3', 'x2'],\n", + " ['x4', 'x0'],\n", + " ['x4', 'x1'],\n", + " ['x4', 'x2'],\n", + " ['x4', 'x3'],\n", + " ['x5', 'x0'],\n", + " ['x5', 'x1'],\n", + " ['x5', 'x2'],\n", + " ['x5', 'x3'],\n", + " ['x5', 'x4'],\n", + " ['x6', 'x0'],\n", + " ['x6', 'x1'],\n", + " ['x6', 'x2'],\n", + " ['x6', 'x3'],\n", + " ['x6', 'x4'],\n", + " ['x6', 'x5'],\n", + " ['x7', 'x0'],\n", + " ['x7', 'x1'],\n", + " ['x7', 'x2'],\n", + " ['x7', 'x3'],\n", + " ['x7', 'x4'],\n", + " ['x7', 'x5'],\n", + " ['x7', 'x6'],\n", + " ['x8', 'x0'],\n", + " ['x8', 'x1'],\n", + " ['x8', 'x2'],\n", + " ['x8', 'x3'],\n", + " ['x8', 'x4'],\n", + " ['x8', 'x5'],\n", + " ['x8', 'x6'],\n", + " ['x8', 'x7'],\n", + " ['x9', 'x0'],\n", + " ['x9', 'x1'],\n", + " ['x9', 'x2'],\n", + " ['x9', 'x3'],\n", + " ['x9', 'x4'],\n", + " ['x9', 'x5'],\n", + " ['x9', 'x6'],\n", + " ['x9', 'x7'],\n", + " ['x9', 'x8']]}},\n", + " {'type': dwave.system.warnings.ChainBreakWarning,\n", + " 'message': 'Lowest-energy samples contain a broken chain',\n", + " 'level': 40,\n", + " 'data': {'target_variables': [165, 2985],\n", + " 'source_variables': ['x3'],\n", + " 'sample_index': 0}},\n", + " {'type': dwave.system.warnings.ChainBreakWarning,\n", + " 'message': 'Lowest-energy samples contain a broken chain',\n", + " 'level': 40,\n", + " 'data': {'target_variables': [225, 3015],\n", + " 'source_variables': ['x5'],\n", + " 'sample_index': 0}},\n", + " {'type': dwave.system.warnings.ChainBreakWarning,\n", + " 'message': 'Lowest-energy samples contain a broken chain',\n", + " 'level': 40,\n", + " 'data': {'target_variables': [255, 3045],\n", + " 'source_variables': ['x7'],\n", + " 'sample_index': 0}},\n", + " {'type': dwave.system.warnings.ChainBreakWarning,\n", + " 'message': 'Lowest-energy samples contain a broken chain',\n", + " 'level': 40,\n", + " 'data': {'target_variables': [120, 3060],\n", + " 'source_variables': ['x8'],\n", + " 'sample_index': 0}},\n", + " {'type': dwave.system.warnings.ChainBreakWarning,\n", + " 'message': 'Lowest-energy samples contain a broken chain',\n", + " 'level': 40,\n", + " 'data': {'target_variables': [135, 3075],\n", + " 'source_variables': ['x9'],\n", + " 'sample_index': 0}},\n", + " {'type': UserWarning,\n", + " 'message': 'All samples have broken chains',\n", + " 'level': 30,\n", + " 'data': {}}]" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sampleset.info[\"warnings\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "2edb5ded", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dwave.system.warnings.ChainBreakWarning" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dwave.system.warnings.ChainBreakWarning" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "7269dbc5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "20" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "G.number_of_nodes()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qomm_env", + "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", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 06ba8eb7366c545448f3531c0a8b37293ee98cd2 Mon Sep 17 00:00:00 2001 From: Barbara Wojtarowicz Date: Wed, 12 Nov 2025 06:43:50 +0100 Subject: [PATCH 14/18] Updates --- QHyper/solvers/base.py | 13 +- .../quantum_annealing/dwave/advantage.py | 54 +- .../id_2_sampleset_adv.npy | Bin .../id_2_sampleset_adv.pkl | Bin .../id_2_sampleset_adv_serializable.pkl | Bin .../id_3_sampleset_adv.npy | Bin .../id_3_sampleset_adv.pkl | Bin .../id_3_sampleset_adv_serializable.pkl | Bin results/id_4_sampleset_adv.npy | Bin 0 -> 178148 bytes results/id_4_sampleset_adv.pkl | Bin 0 -> 178020 bytes ...00_qubo_size=5050_-6767878269440839488.npy | Bin 0 -> 178195 bytes ...00_qubo_size=5050_-6767878269440839488.pkl | Bin 0 -> 178067 bytes ...5050_-6767878269440839488_serializable.pkl | Bin 0 -> 77284 bytes ...100_qubo_size=5050_6008250094015771207.npy | Bin 0 -> 190028 bytes ...100_qubo_size=5050_6008250094015771207.pkl | Bin 0 -> 189900 bytes ...=5050_6008250094015771207_serializable.pkl | Bin 0 -> 82021 bytes results/id_4_sampleset_adv_serializable.pkl | Bin 0 -> 77210 bytes .../sampleset_adv.npy | Bin .../sampleset_adv.pkl | Bin .../sampleset_adv_serializable.pkl | Bin results/t.ipynb | 884 ++++++++++++++++++ t.ipynb | 595 ------------ 22 files changed, 937 insertions(+), 609 deletions(-) rename id_2_sampleset_adv.npy => results/id_2_sampleset_adv.npy (100%) rename id_2_sampleset_adv.pkl => results/id_2_sampleset_adv.pkl (100%) rename id_2_sampleset_adv_serializable.pkl => results/id_2_sampleset_adv_serializable.pkl (100%) rename id_3_sampleset_adv.npy => results/id_3_sampleset_adv.npy (100%) rename id_3_sampleset_adv.pkl => results/id_3_sampleset_adv.pkl (100%) rename id_3_sampleset_adv_serializable.pkl => results/id_3_sampleset_adv_serializable.pkl (100%) create mode 100644 results/id_4_sampleset_adv.npy create mode 100644 results/id_4_sampleset_adv.pkl create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_-6767878269440839488.npy create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_-6767878269440839488.pkl create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_-6767878269440839488_serializable.pkl create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_6008250094015771207.npy create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_6008250094015771207.pkl create mode 100644 results/id_4_sampleset_adv_n=100_qubo_size=5050_6008250094015771207_serializable.pkl create mode 100644 results/id_4_sampleset_adv_serializable.pkl rename sampleset_adv.npy => results/sampleset_adv.npy (100%) rename sampleset_adv.pkl => results/sampleset_adv.pkl (100%) rename sampleset_adv_serializable.pkl => results/sampleset_adv_serializable.pkl (100%) create mode 100644 results/t.ipynb delete mode 100644 t.ipynb diff --git a/QHyper/solvers/base.py b/QHyper/solvers/base.py index 3e466b9..e19221d 100644 --- a/QHyper/solvers/base.py +++ b/QHyper/solvers/base.py @@ -20,6 +20,7 @@ class SolverConfigException(Exception): class SolverException(Exception): pass + @dataclass class SamplesetData: """ @@ -55,8 +56,16 @@ class SamplesetData: (https://dwave-systemdocs.readthedocs.io/en/link_fix/reference/composites/generated/dwave.system.composites.FixedEmbeddingComposite.sample.html#dwave.system.composites.FixedEmbeddingComposite.sample), """ - dwave_sampleset_metadata: np.ndarray - time_measurements: np.ndarray + dwave_sampleset_metadata: np.ndarray | None = None + time_measurements: np.ndarray | None = None + dwave_sampleset: dict | None = None + timing: dict | None = None + problem_id: str | int | float = None + chain_strength: float | None = None + chain_break_fraction: float | None = None + chain_break_method: str | None = None + embedding: dict | None = None + warnings: dict | None = None @dataclass class SolverResult: diff --git a/QHyper/solvers/quantum_annealing/dwave/advantage.py b/QHyper/solvers/quantum_annealing/dwave/advantage.py index c1f5de8..986fc88 100644 --- a/QHyper/solvers/quantum_annealing/dwave/advantage.py +++ b/QHyper/solvers/quantum_annealing/dwave/advantage.py @@ -127,6 +127,8 @@ def solve( qubo_terms, offset = convert_qubo_keys(qubo) bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset) + label = f"n={str(self.problem.G.number_of_nodes())}_" + f"qubo_size={str(len(qubo_terms))}_" + str(hash(tuple(qubo_terms.items()))) + if not self.use_clique_embedding: self.embedding = execute_timed( lambda: find_embedding( @@ -154,6 +156,8 @@ def solve( num_reads=self.num_reads, chain_strength=self.chain_strength, return_embedding=return_embedding, + warnings=dwave.system.warnings.SAVE, + label=label ) # bqm = dimod.BQM.from_qubo(qubo_terms, offset=offset) # sampleset = dimod.ExactSolver().sample(bqm) @@ -163,6 +167,26 @@ def solve( if self.elapse_times: self.times[Timing.SAMPLE_FUNCTION] = end - start + first = next(sampleset.data(sorted_by=["energy"], name="Sample", index=True)) + chain_break_fraction = first.chain_break_fraction + + try: + problem_id = sampleset.info["problem_id"] + embedding_context = sampleset.info["embedding_context"] + chain_strength_extracted = embedding_context["chain_strength"] + chain_break_method = embedding_context["chain_break_method"] + embedding_extracted = embedding_context["embedding"] + timing = sampleset.info["timing"] + warnings_sampleset = sampleset.info.get("warnings", {}) + except Exception as e: + print(f"Could not extract some info from sampleset.info: {e}") + problem_id = None + embedding_context = None + chain_break_method = None + embedding_extracted = None + timing = None + warnings_sampleset = None + arr_to_save = np.array(sampleset, dtype=object) # try: @@ -171,15 +195,14 @@ def solve( # print(f"Could not open DWave Inspector: {e}") try: - with open(f"{saving_path}.pkl" if saving_path else "sampleset_adv.pkl", "wb") as f: + with open(f"{saving_path}_{label}.pkl" if saving_path else f"{label}_sampleset_adv.pkl", "wb") as f: pickle.dump(arr_to_save, f) except Exception as e: print(f"Could not save sampleset to .pkl file: {e}") - try: pickle_bytes = pickle.dumps(sampleset.to_serializable()) - with open(f"{saving_path}_serializable.pkl" if saving_path else "sampleset_adv_serializable.pkl", "wb") as f: + with open(f"{saving_path}_{label}_serializable.pkl" if saving_path else f"{label}_sampleset_adv_serializable.pkl", "wb") as f: f.write(pickle_bytes) except Exception as e: print(f"Could not save serializable sampleset to .pkl file: {e}") @@ -190,12 +213,12 @@ def solve( print(f"Could not pickle sampleset object: {e}") try: - np.save(f"{saving_path}.npy" if saving_path else "sampleset_adv.npy", arr_to_save) + np.save(f"{saving_path}_{label}.npy" if saving_path else f"{label}_sampleset_adv.npy", arr_to_save) except Exception as e: print(f"Could not save times to .npy file: {e}") try: - sampleset.to_file(f"{saving_path}.json" if saving_path else "sampleset_adv.json", cls='json') + sampleset.to_file(f"{saving_path}_{label}.json" if saving_path else f"{label}_sampleset_adv.json", cls='json') except Exception as e: print(f"Could not save sampleset to .json file: {e}") @@ -223,18 +246,25 @@ def solve( if return_metadata: if "timing" in sampleset.info and sampleset.info["timing"]: - sampleset_info = SamplesetData( - time_dict_to_ndarray( + dwave_sampleset_metadata=time_dict_to_ndarray( add_time_units_to_dwave_timing_info( sampleset.info["timing"], TimeUnits.US ) - ), - time_dict_to_ndarray(self.times), ) else: - sampleset_info = SamplesetData( - None, time_dict_to_ndarray(self.times) - ) + dwave_sampleset_metadata=None + sampleset_info = SamplesetData( + dwave_sampleset_metadata=dwave_sampleset_metadata, + time_measurements=time_dict_to_ndarray(self.times), + dwave_sampleset=sampleset, + timing=timing, + problem_id=problem_id, + chain_strength=chain_strength_extracted, + chain_break_fraction=chain_break_fraction, + chain_break_method=chain_break_method, + embedding=embedding_extracted, + warnings=warnings_sampleset, + ) else: sampleset_info = None diff --git a/id_2_sampleset_adv.npy b/results/id_2_sampleset_adv.npy similarity index 100% rename from id_2_sampleset_adv.npy rename to results/id_2_sampleset_adv.npy diff --git a/id_2_sampleset_adv.pkl b/results/id_2_sampleset_adv.pkl similarity index 100% rename from id_2_sampleset_adv.pkl rename to results/id_2_sampleset_adv.pkl diff --git a/id_2_sampleset_adv_serializable.pkl b/results/id_2_sampleset_adv_serializable.pkl similarity index 100% rename from id_2_sampleset_adv_serializable.pkl rename to results/id_2_sampleset_adv_serializable.pkl diff --git a/id_3_sampleset_adv.npy b/results/id_3_sampleset_adv.npy similarity index 100% rename from id_3_sampleset_adv.npy rename to results/id_3_sampleset_adv.npy diff --git a/id_3_sampleset_adv.pkl b/results/id_3_sampleset_adv.pkl similarity index 100% rename from id_3_sampleset_adv.pkl rename to results/id_3_sampleset_adv.pkl diff --git a/id_3_sampleset_adv_serializable.pkl b/results/id_3_sampleset_adv_serializable.pkl similarity index 100% rename from id_3_sampleset_adv_serializable.pkl rename to results/id_3_sampleset_adv_serializable.pkl diff --git a/results/id_4_sampleset_adv.npy b/results/id_4_sampleset_adv.npy new file mode 100644 index 0000000000000000000000000000000000000000..26780af51c9a1209e5b26b010dc0af67ccbfe523 GIT binary patch literal 178148 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