Skip to main content

quantrs2_anneal/dwave/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5#[cfg(feature = "dwave")]
6pub use client::*;
7#[cfg(not(feature = "dwave"))]
8pub use placeholder::*;
9use std::fmt::Write;
10
11#[cfg(feature = "dwave")]
12mod client {
13    use crate::embedding::{Embedding, HardwareGraph, MinorMiner};
14    use crate::ising::{IsingError, IsingModel, QuboModel};
15    use reqwest::Client;
16    use serde::{Deserialize, Serialize};
17    use std::collections::HashMap;
18    use std::fmt::Write;
19    use std::time::{Duration, Instant};
20    use thiserror::Error;
21    use tokio::runtime::Runtime;
22    /// Errors that can occur when interacting with D-Wave API
23    #[derive(Error, Debug)]
24    pub enum DWaveError {
25        /// Error in the underlying Ising model
26        #[error("Ising error: {0}")]
27        IsingError(#[from] IsingError),
28        /// Error with the network request
29        #[error("Network error: {0}")]
30        NetworkError(#[from] reqwest::Error),
31        /// Error parsing the response
32        #[error("Response parsing error: {0}")]
33        ParseError(#[from] serde_json::Error),
34        /// Error with the D-Wave API response
35        #[error("D-Wave API error: {0}")]
36        ApiError(String),
37        /// Error with the authentication credentials
38        #[error("Authentication error: {0}")]
39        AuthError(String),
40        /// Error with the tokio runtime
41        #[error("Runtime error: {0}")]
42        RuntimeError(String),
43        /// Error with the problem formulation
44        #[error("Problem formulation error: {0}")]
45        ProblemError(String),
46        /// Error with embedding
47        #[error("Embedding error: {0}")]
48        EmbeddingError(String),
49        /// Error with hybrid solver
50        #[error("Hybrid solver error: {0}")]
51        HybridSolverError(String),
52        /// Error with problem status
53        #[error("Problem status error: {0}")]
54        StatusError(String),
55        /// Error with batch operations
56        #[error("Batch operation error: {0}")]
57        BatchError(String),
58        /// Error with solver configuration
59        #[error("Solver configuration error: {0}")]
60        SolverConfigError(String),
61        /// Timeout error
62        #[error("Operation timed out: {0}")]
63        TimeoutError(String),
64    }
65    /// Result type for D-Wave operations
66    pub type DWaveResult<T> = Result<T, DWaveError>;
67    /// D-Wave solver information
68    #[derive(Debug, Clone, Serialize, Deserialize)]
69    pub struct SolverInfo {
70        /// ID of the solver
71        pub id: String,
72        /// Name of the solver
73        pub name: String,
74        /// Description of the solver
75        pub description: String,
76        /// Number of qubits
77        pub num_qubits: usize,
78        /// Connectivity information
79        pub connectivity: SolverConnectivity,
80        /// Properties of the solver
81        pub properties: SolverProperties,
82    }
83    /// D-Wave solver connectivity
84    #[derive(Debug, Clone, Serialize, Deserialize)]
85    pub struct SolverConnectivity {
86        /// Type of connectivity (e.g., "chimera", "pegasus")
87        #[serde(rename = "type")]
88        pub type_: String,
89        /// Parameters for the connectivity
90        #[serde(flatten)]
91        pub params: serde_json::Value,
92    }
93    /// D-Wave solver properties
94    #[derive(Debug, Clone, Serialize, Deserialize)]
95    pub struct SolverProperties {
96        /// Supported parameters
97        pub parameters: serde_json::Value,
98        /// Additional properties
99        #[serde(flatten)]
100        pub other: serde_json::Value,
101    }
102    /// D-Wave problem submission parameters
103    #[derive(Debug, Clone, Serialize, Deserialize)]
104    pub struct ProblemParams {
105        /// Number of reads/samples to take
106        pub num_reads: usize,
107        /// Annealing time in microseconds
108        pub annealing_time: usize,
109        /// Programming thermalization in microseconds
110        #[serde(rename = "programming_thermalization")]
111        pub programming_therm: usize,
112        /// Read-out thermalization in microseconds
113        #[serde(rename = "readout_thermalization")]
114        pub readout_therm: usize,
115        /// Flux biases for each qubit (optional)
116        #[serde(rename = "flux_biases", skip_serializing_if = "Option::is_none")]
117        pub flux_biases: Option<Vec<f64>>,
118        /// Per-qubit flux bias values (optional, alternative format)
119        #[serde(rename = "flux_bias", skip_serializing_if = "Option::is_none")]
120        pub flux_bias_map: Option<serde_json::Map<String, serde_json::Value>>,
121        /// Additional parameters
122        #[serde(flatten)]
123        pub other: serde_json::Value,
124    }
125    impl Default for ProblemParams {
126        fn default() -> Self {
127            Self {
128                num_reads: 1000,
129                annealing_time: 20,
130                programming_therm: 1000,
131                readout_therm: 0,
132                flux_biases: None,
133                flux_bias_map: None,
134                other: serde_json::Value::Object(serde_json::Map::new()),
135            }
136        }
137    }
138    /// D-Wave problem submission
139    #[derive(Debug, Clone, Serialize, Deserialize)]
140    pub struct Problem {
141        /// The linear terms (h_i values for Ising, Q_ii for QUBO)
142        #[serde(rename = "linear")]
143        pub linear_terms: serde_json::Value,
144        /// The quadratic terms (J_ij values for Ising, Q_ij for QUBO)
145        #[serde(rename = "quadratic")]
146        pub quadratic_terms: serde_json::Value,
147        /// The type of problem (ising or qubo)
148        #[serde(rename = "type")]
149        pub type_: String,
150        /// The solver to use
151        pub solver: String,
152        /// The parameters for the problem
153        pub params: ProblemParams,
154    }
155    /// D-Wave problem solution
156    #[derive(Debug, Clone, Serialize, Deserialize)]
157    pub struct Solution {
158        /// The energy of each sample
159        pub energies: Vec<f64>,
160        /// The occurrences of each sample
161        pub occurrences: Vec<usize>,
162        /// The solutions (spin values for Ising, binary values for QUBO)
163        pub solutions: Vec<Vec<i8>>,
164        /// The number of samples
165        pub num_samples: usize,
166        /// The problem ID
167        pub problem_id: String,
168        /// The solver used
169        pub solver: String,
170        /// The timing information
171        pub timing: serde_json::Value,
172    }
173    /// Enhanced solver types for Leap
174    #[derive(Debug, Clone, Serialize, Deserialize)]
175    pub enum SolverType {
176        /// Quantum annealing processor
177        #[serde(rename = "qpu")]
178        QuantumProcessor,
179        /// Hybrid classical-quantum solver
180        #[serde(rename = "hybrid")]
181        Hybrid,
182        /// Discrete Quadratic Model solver
183        #[serde(rename = "dqm")]
184        DiscreteQuadraticModel,
185        /// Constrained Quadratic Model solver
186        #[serde(rename = "cqm")]
187        ConstrainedQuadraticModel,
188        /// Software solver/simulator
189        #[serde(rename = "software")]
190        Software,
191    }
192    /// Solver category for filtering
193    #[derive(Debug, Clone, PartialEq, Eq)]
194    pub enum SolverCategory {
195        /// Quantum processing units
196        QPU,
197        /// Hybrid solvers
198        Hybrid,
199        /// Software-based solvers
200        Software,
201        /// All solver types
202        All,
203    }
204    /// Problem status tracking
205    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
206    pub enum ProblemStatus {
207        /// Problem is being processed
208        #[serde(rename = "IN_PROGRESS")]
209        InProgress,
210        /// Problem completed successfully
211        #[serde(rename = "COMPLETED")]
212        Completed,
213        /// Problem failed
214        #[serde(rename = "FAILED")]
215        Failed,
216        /// Problem was cancelled
217        #[serde(rename = "CANCELLED")]
218        Cancelled,
219        /// Problem is pending
220        #[serde(rename = "PENDING")]
221        Pending,
222    }
223    /// Problem metadata and tracking
224    #[derive(Debug, Clone, Serialize, Deserialize)]
225    pub struct ProblemInfo {
226        /// Problem ID
227        pub id: String,
228        /// Problem status
229        pub status: ProblemStatus,
230        /// Submission time
231        pub submitted_on: String,
232        /// Solver used
233        pub solver: String,
234        /// Problem type
235        #[serde(rename = "type")]
236        pub problem_type: String,
237        /// Parameters used
238        pub params: serde_json::Value,
239        /// Additional metadata
240        #[serde(flatten)]
241        pub metadata: serde_json::Value,
242    }
243    /// Enhanced solver information with Leap features
244    #[derive(Debug, Clone, Serialize, Deserialize)]
245    pub struct LeapSolverInfo {
246        /// Solver ID
247        pub id: String,
248        /// Solver name
249        pub name: String,
250        /// Solver description
251        pub description: String,
252        /// Solver type
253        #[serde(rename = "category")]
254        pub solver_type: SolverType,
255        /// Status (online/offline)
256        pub status: String,
257        /// Solver properties
258        pub properties: serde_json::Value,
259        /// Supported problem types
260        pub problem_types: Vec<String>,
261        /// Average queue time
262        pub avg_load: Option<f64>,
263        /// Whether solver is available
264        pub available: bool,
265    }
266    /// Custom annealing schedule
267    #[derive(Debug, Clone, Serialize, Deserialize)]
268    pub struct AnnealingSchedule {
269        /// Time points in microseconds
270        pub schedule: Vec<(f64, f64)>,
271    }
272    impl AnnealingSchedule {
273        /// Create a linear annealing schedule
274        pub fn linear(annealing_time: f64) -> Self {
275            Self {
276                schedule: vec![(0.0, 1.0), (annealing_time, 0.0)],
277            }
278        }
279        /// Create a pause-and-ramp schedule
280        pub fn pause_and_ramp(annealing_time: f64, pause_start: f64, pause_duration: f64) -> Self {
281            Self {
282                schedule: vec![
283                    (0.0, 1.0),
284                    (pause_start, 1.0 - pause_start / annealing_time),
285                    (
286                        pause_start + pause_duration,
287                        1.0 - pause_start / annealing_time,
288                    ),
289                    (annealing_time, 0.0),
290                ],
291            }
292        }
293        /// Create a custom schedule from points
294        pub fn custom(points: Vec<(f64, f64)>) -> Self {
295            Self { schedule: points }
296        }
297    }
298    /// Advanced problem parameters for Leap
299    #[derive(Debug, Clone, Serialize, Deserialize)]
300    pub struct AdvancedProblemParams {
301        /// Number of reads/samples
302        pub num_reads: usize,
303        /// Custom annealing schedule
304        #[serde(skip_serializing_if = "Option::is_none")]
305        pub anneal_schedule: Option<AnnealingSchedule>,
306        /// Programming thermalization
307        #[serde(skip_serializing_if = "Option::is_none")]
308        pub programming_thermalization: Option<usize>,
309        /// Readout thermalization
310        #[serde(skip_serializing_if = "Option::is_none")]
311        pub readout_thermalization: Option<usize>,
312        /// Auto-scale flag
313        #[serde(skip_serializing_if = "Option::is_none")]
314        pub auto_scale: Option<bool>,
315        /// Chain strength
316        #[serde(skip_serializing_if = "Option::is_none")]
317        pub chain_strength: Option<f64>,
318        /// Flux biases
319        #[serde(skip_serializing_if = "Option::is_none")]
320        pub flux_biases: Option<HashMap<String, f64>>,
321        /// Additional parameters
322        #[serde(flatten)]
323        pub extra: HashMap<String, serde_json::Value>,
324    }
325    impl Default for AdvancedProblemParams {
326        fn default() -> Self {
327            Self {
328                num_reads: 1000,
329                anneal_schedule: None,
330                programming_thermalization: Some(1000),
331                readout_thermalization: Some(0),
332                auto_scale: Some(true),
333                chain_strength: None,
334                flux_biases: None,
335                extra: HashMap::new(),
336            }
337        }
338    }
339    /// Hybrid solver parameters
340    #[derive(Debug, Clone, Serialize, Deserialize)]
341    pub struct HybridSolverParams {
342        /// Time limit in seconds
343        #[serde(skip_serializing_if = "Option::is_none")]
344        pub time_limit: Option<f64>,
345        /// Maximum number of variables
346        #[serde(skip_serializing_if = "Option::is_none")]
347        pub max_variables: Option<usize>,
348        /// Additional solver-specific parameters
349        #[serde(flatten)]
350        pub extra: HashMap<String, serde_json::Value>,
351    }
352    impl Default for HybridSolverParams {
353        fn default() -> Self {
354            Self {
355                time_limit: Some(5.0),
356                max_variables: None,
357                extra: HashMap::new(),
358            }
359        }
360    }
361    /// Performance metrics for problems
362    #[derive(Debug, Clone)]
363    pub struct ProblemMetrics {
364        /// Total execution time
365        pub total_time: Duration,
366        /// Queue time
367        pub queue_time: Duration,
368        /// Solver access time
369        pub access_time: Duration,
370        /// Programming time
371        pub programming_time: Duration,
372        /// Sampling time
373        pub sampling_time: Duration,
374        /// Readout time
375        pub readout_time: Duration,
376        /// Best energy found
377        pub best_energy: f64,
378        /// Number of valid solutions
379        pub num_valid_solutions: usize,
380        /// Chain break fraction
381        pub chain_break_fraction: Option<f64>,
382    }
383    /// Batch problem submission result
384    #[derive(Debug)]
385    pub struct BatchSubmissionResult {
386        /// List of submitted problem IDs
387        pub problem_ids: Vec<String>,
388        /// Success/failure status for each problem
389        pub statuses: Vec<Result<String, DWaveError>>,
390        /// Total submission time
391        pub submission_time: Duration,
392    }
393    /// Solver selection criteria
394    #[derive(Debug, Clone)]
395    pub struct SolverSelector {
396        /// Solver category filter
397        pub category: SolverCategory,
398        /// Minimum number of qubits
399        pub min_qubits: Option<usize>,
400        /// Maximum queue time preference
401        pub max_queue_time: Option<f64>,
402        /// Prefer online solvers
403        pub online_only: bool,
404        /// Specific solver name pattern
405        pub name_pattern: Option<String>,
406        /// Topology preference
407        pub topology_preference: Option<String>,
408    }
409    impl Default for SolverSelector {
410        fn default() -> Self {
411            Self {
412                category: SolverCategory::All,
413                min_qubits: None,
414                max_queue_time: None,
415                online_only: true,
416                name_pattern: None,
417                topology_preference: None,
418            }
419        }
420    }
421    /// Problem embedding configuration
422    #[derive(Debug, Clone)]
423    pub struct EmbeddingConfig {
424        /// Use automatic embedding
425        pub auto_embed: bool,
426        /// Embedding timeout
427        pub timeout: Duration,
428        /// Chain strength calculation method
429        pub chain_strength_method: ChainStrengthMethod,
430        /// Custom embedding (if not auto-embedding)
431        pub custom_embedding: Option<Embedding>,
432        /// Embedding optimization level
433        pub optimization_level: usize,
434    }
435    /// Chain strength calculation methods
436    #[derive(Debug, Clone)]
437    pub enum ChainStrengthMethod {
438        /// Automatic calculation
439        Auto,
440        /// Fixed value
441        Fixed(f64),
442        /// Based on problem coupling strengths
443        Adaptive(f64),
444    }
445    impl Default for EmbeddingConfig {
446        fn default() -> Self {
447            Self {
448                auto_embed: true,
449                timeout: Duration::from_secs(30),
450                chain_strength_method: ChainStrengthMethod::Auto,
451                custom_embedding: None,
452                optimization_level: 1,
453            }
454        }
455    }
456    /// Enhanced D-Wave Leap cloud service client
457    #[derive(Debug)]
458    pub struct DWaveClient {
459        /// The HTTP client for making API requests
460        client: Client,
461        /// The API endpoint
462        endpoint: String,
463        /// The API token
464        token: String,
465        /// The tokio runtime for async requests
466        runtime: Runtime,
467        /// Default solver selector
468        default_solver_selector: SolverSelector,
469        /// Default embedding configuration
470        default_embedding_config: EmbeddingConfig,
471        /// Retry configuration
472        max_retries: usize,
473        /// Request timeout
474        request_timeout: Duration,
475        /// Default problem timeout
476        problem_timeout: Duration,
477    }
478    impl DWaveClient {
479        /// Create a new enhanced D-Wave Leap client
480        pub fn new(token: impl Into<String>, endpoint: Option<String>) -> DWaveResult<Self> {
481            Self::with_config(
482                token,
483                endpoint,
484                SolverSelector::default(),
485                EmbeddingConfig::default(),
486            )
487        }
488        /// Create a D-Wave client with custom configuration
489        pub fn with_config(
490            token: impl Into<String>,
491            endpoint: Option<String>,
492            solver_selector: SolverSelector,
493            embedding_config: EmbeddingConfig,
494        ) -> DWaveResult<Self> {
495            let client = Client::builder()
496                .timeout(Duration::from_secs(300))
497                .build()
498                .map_err(DWaveError::NetworkError)?;
499            let runtime = Runtime::new().map_err(|e| DWaveError::RuntimeError(e.to_string()))?;
500            let endpoint =
501                endpoint.unwrap_or_else(|| "https://cloud.dwavesys.com/sapi/v2".to_string());
502            Ok(Self {
503                client,
504                endpoint,
505                token: token.into(),
506                runtime,
507                default_solver_selector: solver_selector,
508                default_embedding_config: embedding_config,
509                max_retries: 3,
510                request_timeout: Duration::from_secs(300),
511                problem_timeout: Duration::from_secs(1800),
512            })
513        }
514        /// Get a list of available solvers
515        pub fn get_solvers(&self) -> DWaveResult<Vec<SolverInfo>> {
516            let url = format!("{}/solvers/remote", self.endpoint);
517            self.runtime.block_on(async {
518                let response = self
519                    .client
520                    .get(&url)
521                    .header("Authorization", format!("token {}", self.token))
522                    .send()
523                    .await?;
524                if !response.status().is_success() {
525                    let status = response.status();
526                    let error_text = response.text().await?;
527                    return Err(DWaveError::ApiError(format!(
528                        "Error getting solvers: {status} - {error_text}"
529                    )));
530                }
531                let solvers: Vec<SolverInfo> = response.json().await?;
532                Ok(solvers)
533            })
534        }
535        /// Submit an Ising model to D-Wave
536        pub fn submit_ising(
537            &self,
538            model: &IsingModel,
539            solver_id: &str,
540            params: ProblemParams,
541        ) -> DWaveResult<Solution> {
542            let mut linear_terms = serde_json::Map::new();
543            for (qubit, bias) in model.biases() {
544                let value = serde_json::to_value(bias).map_err(|e| {
545                    DWaveError::ProblemError(format!("Failed to serialize bias: {e}"))
546                })?;
547                linear_terms.insert(qubit.to_string(), value);
548            }
549            let mut quadratic_terms = serde_json::Map::new();
550            for coupling in model.couplings() {
551                let key = format!("{},{}", coupling.i, coupling.j);
552                let value = serde_json::to_value(coupling.strength).map_err(|e| {
553                    DWaveError::ProblemError(format!("Failed to serialize coupling: {e}"))
554                })?;
555                quadratic_terms.insert(key, value);
556            }
557            let problem = Problem {
558                linear_terms: serde_json::Value::Object(linear_terms),
559                quadratic_terms: serde_json::Value::Object(quadratic_terms),
560                type_: "ising".to_string(),
561                solver: solver_id.to_string(),
562                params,
563            };
564            self.submit_problem(&problem)
565        }
566        /// Submit a QUBO model to D-Wave
567        pub fn submit_qubo(
568            &self,
569            model: &QuboModel,
570            solver_id: &str,
571            params: ProblemParams,
572        ) -> DWaveResult<Solution> {
573            let mut linear_terms = serde_json::Map::new();
574            for (var, value) in model.linear_terms() {
575                let json_value = serde_json::to_value(value).map_err(|e| {
576                    DWaveError::ProblemError(format!("Failed to serialize linear term: {e}"))
577                })?;
578                linear_terms.insert(var.to_string(), json_value);
579            }
580            let mut quadratic_terms = serde_json::Map::new();
581            for (var1, var2, value) in model.quadratic_terms() {
582                let key = format!("{var1},{var2}");
583                let json_value = serde_json::to_value(value).map_err(|e| {
584                    DWaveError::ProblemError(format!("Failed to serialize quadratic term: {e}"))
585                })?;
586                quadratic_terms.insert(key, json_value);
587            }
588            let problem = Problem {
589                linear_terms: serde_json::Value::Object(linear_terms),
590                quadratic_terms: serde_json::Value::Object(quadratic_terms),
591                type_: "qubo".to_string(),
592                solver: solver_id.to_string(),
593                params,
594            };
595            self.submit_problem(&problem)
596        }
597        /// Submit an Ising model with flux bias optimization
598        pub fn submit_ising_with_flux_bias(
599            &self,
600            model: &IsingModel,
601            solver_id: &str,
602            params: ProblemParams,
603            flux_biases: &std::collections::HashMap<usize, f64>,
604        ) -> DWaveResult<Solution> {
605            let mut params_with_flux = params;
606            let mut flux_map = serde_json::Map::new();
607            for (qubit, &flux_bias) in flux_biases {
608                let value = serde_json::to_value(flux_bias).map_err(|e| {
609                    DWaveError::ProblemError(format!("Failed to serialize flux bias: {e}"))
610                })?;
611                flux_map.insert(qubit.to_string(), value);
612            }
613            params_with_flux.flux_bias_map = Some(flux_map);
614            self.submit_ising(model, solver_id, params_with_flux)
615        }
616        /// Submit a problem to D-Wave
617        fn submit_problem(&self, problem: &Problem) -> DWaveResult<Solution> {
618            let url = format!("{}/problems", self.endpoint);
619            self.runtime.block_on(async {
620                let response = self
621                    .client
622                    .post(&url)
623                    .header("Authorization", format!("token {}", self.token))
624                    .header("Content-Type", "application/json")
625                    .json(problem)
626                    .send()
627                    .await?;
628                if !response.status().is_success() {
629                    let status = response.status();
630                    let error_text = response.text().await?;
631                    return Err(DWaveError::ApiError(format!(
632                        "Error submitting problem: {status} - {error_text}"
633                    )));
634                }
635                let submit_response: serde_json::Value = response.json().await?;
636                let problem_id = submit_response["id"].as_str().ok_or_else(|| {
637                    let error_msg = String::from("Failed to extract problem ID from response");
638                    DWaveError::ApiError(error_msg)
639                })?;
640                let result_url = format!("{}/problems/{}", self.endpoint, problem_id);
641                let mut attempts = 0;
642                const MAX_ATTEMPTS: usize = 60;
643                while attempts < MAX_ATTEMPTS {
644                    let status_response = self
645                        .client
646                        .get(&result_url)
647                        .header("Authorization", format!("token {}", self.token))
648                        .send()
649                        .await?;
650                    if !status_response.status().is_success() {
651                        let status = status_response.status();
652                        let error_text = status_response.text().await?;
653                        return Err(DWaveError::ApiError(format!(
654                            "Error getting problem status: {status} - {error_text}"
655                        )));
656                    }
657                    let status: serde_json::Value = status_response.json().await?;
658                    if let Some(state) = status["state"].as_str() {
659                        if state == "COMPLETED" {
660                            return Ok(Solution {
661                                energies: serde_json::from_value(status["energies"].clone())?,
662                                occurrences: serde_json::from_value(status["occurrences"].clone())?,
663                                solutions: serde_json::from_value(status["solutions"].clone())?,
664                                num_samples: status["num_samples"].as_u64().unwrap_or(0) as usize,
665                                problem_id: problem_id.to_string(),
666                                solver: problem.solver.clone(),
667                                timing: status["timing"].clone(),
668                            });
669                        } else if state == "FAILED" {
670                            let error = status["error"].as_str().unwrap_or("Unknown error");
671                            return Err(DWaveError::ApiError(format!("Problem failed: {error}")));
672                        }
673                    }
674                    tokio::time::sleep(Duration::from_secs(5)).await;
675                    attempts += 1;
676                }
677                Err(DWaveError::ApiError(
678                    "Timeout waiting for problem solution".into(),
679                ))
680            })
681        }
682        /// Get enhanced Leap solver information
683        pub fn get_leap_solvers(&self) -> DWaveResult<Vec<LeapSolverInfo>> {
684            let url = format!("{}/solvers/remote", self.endpoint);
685            self.runtime.block_on(async {
686                let response = self
687                    .client
688                    .get(&url)
689                    .header("Authorization", format!("token {}", self.token))
690                    .send()
691                    .await?;
692                if !response.status().is_success() {
693                    let status = response.status();
694                    let error_text = response.text().await?;
695                    return Err(DWaveError::ApiError(format!(
696                        "Error getting Leap solvers: {status} - {error_text}"
697                    )));
698                }
699                let solvers: Vec<LeapSolverInfo> = response.json().await?;
700                Ok(solvers)
701            })
702        }
703        /// Select optimal solver based on criteria
704        pub fn select_solver(
705            &self,
706            selector: Option<&SolverSelector>,
707        ) -> DWaveResult<LeapSolverInfo> {
708            let selector = selector.unwrap_or(&self.default_solver_selector);
709            let solvers = self.get_leap_solvers()?;
710            let filtered_solvers: Vec<_> = solvers
711                .into_iter()
712                .filter(|solver| {
713                    let category_match = match selector.category {
714                        SolverCategory::QPU => {
715                            matches!(solver.solver_type, SolverType::QuantumProcessor)
716                        }
717                        SolverCategory::Hybrid => {
718                            matches!(solver.solver_type, SolverType::Hybrid)
719                        }
720                        SolverCategory::Software => {
721                            matches!(solver.solver_type, SolverType::Software)
722                        }
723                        SolverCategory::All => true,
724                    };
725                    let availability_match = !selector.online_only || solver.available;
726                    let name_match = selector
727                        .name_pattern
728                        .as_ref()
729                        .map(|pattern| solver.name.contains(pattern))
730                        .unwrap_or(true);
731                    let queue_match = selector
732                        .max_queue_time
733                        .map(|max_time| solver.avg_load.unwrap_or(0.0) <= max_time)
734                        .unwrap_or(true);
735                    category_match && availability_match && name_match && queue_match
736                })
737                .collect();
738            if filtered_solvers.is_empty() {
739                return Err(DWaveError::SolverConfigError(
740                    "No solvers match the selection criteria".to_string(),
741                ));
742            }
743            let mut best_solver = filtered_solvers[0].clone();
744            for solver in &filtered_solvers[1..] {
745                let current_load = best_solver.avg_load.unwrap_or(f64::INFINITY);
746                let candidate_load = solver.avg_load.unwrap_or(f64::INFINITY);
747                if candidate_load < current_load {
748                    best_solver = solver.clone();
749                }
750            }
751            Ok(best_solver)
752        }
753        /// Submit problem with automatic embedding
754        pub fn submit_ising_with_embedding(
755            &self,
756            model: &IsingModel,
757            solver_id: Option<&str>,
758            params: Option<AdvancedProblemParams>,
759            embedding_config: Option<&EmbeddingConfig>,
760        ) -> DWaveResult<Solution> {
761            let embedding_config = embedding_config.unwrap_or(&self.default_embedding_config);
762            let solver = if let Some(id) = solver_id {
763                self.get_leap_solvers()?
764                    .into_iter()
765                    .find(|s| s.id == id)
766                    .ok_or_else(|| {
767                        DWaveError::SolverConfigError(format!("Solver {id} not found"))
768                    })?
769            } else {
770                self.select_solver(None)?
771            };
772            if matches!(solver.solver_type, SolverType::QuantumProcessor) {
773                self.submit_with_auto_embedding(model, &solver, params, embedding_config)
774            } else {
775                let legacy_params = if let Some(p) = params {
776                    let flux_bias_map = if let Some(fb) = p.flux_biases {
777                        let mut map = serde_json::Map::new();
778                        for (k, v) in fb {
779                            let value = serde_json::to_value(v).map_err(|e| {
780                                DWaveError::ProblemError(format!(
781                                    "Failed to serialize flux bias: {e}"
782                                ))
783                            })?;
784                            map.insert(k, value);
785                        }
786                        Some(map)
787                    } else {
788                        None
789                    };
790                    ProblemParams {
791                        num_reads: p.num_reads,
792                        annealing_time: 20,
793                        programming_therm: p.programming_thermalization.unwrap_or(1000),
794                        readout_therm: p.readout_thermalization.unwrap_or(0),
795                        flux_biases: None,
796                        flux_bias_map,
797                        other: serde_json::Value::Object(serde_json::Map::new()),
798                    }
799                } else {
800                    ProblemParams::default()
801                };
802                self.submit_ising(model, &solver.id, legacy_params)
803            }
804        }
805        /// Submit with automatic embedding for QPU solvers
806        fn submit_with_auto_embedding(
807            &self,
808            model: &IsingModel,
809            solver: &LeapSolverInfo,
810            params: Option<AdvancedProblemParams>,
811            embedding_config: &EmbeddingConfig,
812        ) -> DWaveResult<Solution> {
813            let params = params.unwrap_or_default();
814            let mut logical_edges = Vec::new();
815            for coupling in model.couplings() {
816                logical_edges.push((coupling.i, coupling.j));
817            }
818            let hardware_graph = self.get_solver_topology(&solver.id)?;
819            let embedding = if let Some(custom_emb) = &embedding_config.custom_embedding {
820                custom_emb.clone()
821            } else {
822                let embedder = MinorMiner {
823                    max_tries: 10 * embedding_config.optimization_level,
824                    ..Default::default()
825                };
826                embedder
827                    .find_embedding(&logical_edges, model.num_qubits, &hardware_graph)
828                    .map_err(|e| DWaveError::EmbeddingError(e.to_string()))?
829            };
830            let chain_strength =
831                Self::calculate_chain_strength(model, &embedding_config.chain_strength_method);
832            let embedded_problem = Self::embed_problem(model, &embedding, chain_strength)?;
833            self.submit_embedded_problem(&embedded_problem, solver, params)
834        }
835        /// Get solver topology information
836        fn get_solver_topology(&self, solver_id: &str) -> DWaveResult<HardwareGraph> {
837            let url = format!("{}/solvers/remote/{}", self.endpoint, solver_id);
838            let topology_info = self.runtime.block_on(async {
839                let response = self
840                    .client
841                    .get(&url)
842                    .header("Authorization", format!("token {}", self.token))
843                    .send()
844                    .await?;
845                if !response.status().is_success() {
846                    let status = response.status();
847                    let error_text = response.text().await?;
848                    return Err(DWaveError::ApiError(format!(
849                        "Error getting solver topology: {status} - {error_text}"
850                    )));
851                }
852                let solver_data: serde_json::Value = response.json().await?;
853                Ok(solver_data)
854            })?;
855            let properties = &topology_info["properties"];
856            if let Some(edges) = properties["couplers"].as_array() {
857                let mut hardware_edges = Vec::new();
858                for edge in edges {
859                    if let (Some(i), Some(j)) = (edge[0].as_u64(), edge[1].as_u64()) {
860                        hardware_edges.push((i as usize, j as usize));
861                    }
862                }
863                let num_qubits = properties["qubits"]
864                    .as_array()
865                    .map(|arr| arr.len())
866                    .unwrap_or(0);
867                Ok(HardwareGraph::new_custom(num_qubits, hardware_edges))
868            } else {
869                Err(DWaveError::SolverConfigError(
870                    "Could not parse solver topology".to_string(),
871                ))
872            }
873        }
874        /// Calculate appropriate chain strength
875        fn calculate_chain_strength(model: &IsingModel, method: &ChainStrengthMethod) -> f64 {
876            match method {
877                ChainStrengthMethod::Auto => {
878                    let max_coupling = model
879                        .couplings()
880                        .iter()
881                        .map(|c| c.strength.abs())
882                        .fold(0.0, f64::max);
883                    let max_bias = (0..model.num_qubits)
884                        .filter_map(|i| model.get_bias(i).ok())
885                        .fold(0.0_f64, |acc, bias| acc.max(bias.abs()));
886                    2.0 * (max_coupling.max(max_bias))
887                }
888                ChainStrengthMethod::Fixed(value) => *value,
889                ChainStrengthMethod::Adaptive(multiplier) => {
890                    let avg_coupling = model
891                        .couplings()
892                        .iter()
893                        .map(|c| c.strength.abs())
894                        .sum::<f64>()
895                        / model.couplings().len().max(1) as f64;
896                    multiplier * avg_coupling
897                }
898            }
899        }
900        /// Embed logical problem onto physical hardware
901        fn embed_problem(
902            model: &IsingModel,
903            embedding: &Embedding,
904            chain_strength: f64,
905        ) -> DWaveResult<IsingModel> {
906            let mut embedded_model = IsingModel::new(0);
907            let max_qubit = embedding
908                .chains
909                .values()
910                .flat_map(|chain| chain.iter())
911                .max()
912                .copied()
913                .unwrap_or(0);
914            embedded_model = IsingModel::new(max_qubit + 1);
915            for (var, chain) in &embedding.chains {
916                if let Ok(bias) = model.get_bias(*var) {
917                    if bias != 0.0 {
918                        let bias_per_qubit = bias / chain.len() as f64;
919                        for &qubit in chain {
920                            embedded_model
921                                .set_bias(qubit, bias_per_qubit)
922                                .map_err(|e| DWaveError::EmbeddingError(e.to_string()))?;
923                        }
924                    }
925                }
926            }
927            for coupling in model.couplings() {
928                if let (Some(chain1), Some(chain2)) = (
929                    embedding.chains.get(&coupling.i),
930                    embedding.chains.get(&coupling.j),
931                ) {
932                    for &q1 in chain1 {
933                        for &q2 in chain2 {
934                            embedded_model
935                                .set_coupling(q1, q2, coupling.strength)
936                                .map_err(|e| DWaveError::EmbeddingError(e.to_string()))?;
937                        }
938                    }
939                }
940            }
941            for chain in embedding.chains.values() {
942                for window in chain.windows(2) {
943                    if let [q1, q2] = window {
944                        embedded_model
945                            .set_coupling(*q1, *q2, -chain_strength)
946                            .map_err(|e| DWaveError::EmbeddingError(e.to_string()))?;
947                    }
948                }
949            }
950            Ok(embedded_model)
951        }
952        /// Submit an embedded problem
953        fn submit_embedded_problem(
954            &self,
955            embedded_model: &IsingModel,
956            solver: &LeapSolverInfo,
957            params: AdvancedProblemParams,
958        ) -> DWaveResult<Solution> {
959            let flux_bias_map = if let Some(fb) = params.flux_biases {
960                let mut map = serde_json::Map::new();
961                for (k, v) in fb {
962                    let value = serde_json::to_value(v).map_err(|e| {
963                        DWaveError::ProblemError(format!("Failed to serialize flux bias: {e}"))
964                    })?;
965                    map.insert(k, value);
966                }
967                Some(map)
968            } else {
969                None
970            };
971            let legacy_params = ProblemParams {
972                num_reads: params.num_reads,
973                annealing_time: params
974                    .anneal_schedule
975                    .as_ref()
976                    .and_then(|schedule| schedule.schedule.last())
977                    .map(|(time, _)| *time as usize)
978                    .unwrap_or(20),
979                programming_therm: params.programming_thermalization.unwrap_or(1000),
980                readout_therm: params.readout_thermalization.unwrap_or(0),
981                flux_biases: None,
982                flux_bias_map,
983                other: serde_json::Value::Object(serde_json::Map::new()),
984            };
985            self.submit_ising(embedded_model, &solver.id, legacy_params)
986        }
987        /// Submit hybrid solver problem
988        pub fn submit_hybrid(
989            &self,
990            model: &IsingModel,
991            solver_id: Option<&str>,
992            params: Option<HybridSolverParams>,
993        ) -> DWaveResult<Solution> {
994            let params = params.unwrap_or_default();
995            let solver = if let Some(id) = solver_id {
996                self.get_leap_solvers()?
997                    .into_iter()
998                    .find(|s| s.id == id)
999                    .ok_or_else(|| {
1000                        DWaveError::SolverConfigError(format!("Solver {id} not found"))
1001                    })?
1002            } else {
1003                let hybrid_selector = SolverSelector {
1004                    category: SolverCategory::Hybrid,
1005                    ..Default::default()
1006                };
1007                self.select_solver(Some(&hybrid_selector))?
1008            };
1009            let mut linear_terms = serde_json::Map::new();
1010            for (qubit, bias) in model.biases() {
1011                let value = serde_json::to_value(bias).map_err(|e| {
1012                    DWaveError::ProblemError(format!("Failed to serialize bias: {e}"))
1013                })?;
1014                linear_terms.insert(qubit.to_string(), value);
1015            }
1016            let mut quadratic_terms = serde_json::Map::new();
1017            for coupling in model.couplings() {
1018                let key = format!("{},{}", coupling.i, coupling.j);
1019                let value = serde_json::to_value(coupling.strength).map_err(|e| {
1020                    DWaveError::ProblemError(format!("Failed to serialize coupling: {e}"))
1021                })?;
1022                quadratic_terms.insert(key, value);
1023            }
1024            let mut hybrid_params = params.extra.clone();
1025            if let Some(time_limit) = params.time_limit {
1026                let value = serde_json::to_value(time_limit).map_err(|e| {
1027                    DWaveError::ProblemError(format!("Failed to serialize time_limit: {e}"))
1028                })?;
1029                hybrid_params.insert("time_limit".to_string(), value);
1030            }
1031            let problem = Problem {
1032                linear_terms: serde_json::Value::Object(linear_terms),
1033                quadratic_terms: serde_json::Value::Object(quadratic_terms),
1034                type_: "ising".to_string(),
1035                solver: solver.id,
1036                params: ProblemParams {
1037                    num_reads: 1,
1038                    annealing_time: 1,
1039                    programming_therm: 0,
1040                    readout_therm: 0,
1041                    flux_biases: None,
1042                    flux_bias_map: None,
1043                    other: serde_json::Value::Object(
1044                        hybrid_params.into_iter().map(|(k, v)| (k, v)).collect(),
1045                    ),
1046                },
1047            };
1048            self.submit_problem(&problem)
1049        }
1050        /// Get problem status
1051        pub fn get_problem_status(&self, problem_id: &str) -> DWaveResult<ProblemInfo> {
1052            let url = format!("{}/problems/{}", self.endpoint, problem_id);
1053            self.runtime.block_on(async {
1054                let response = self
1055                    .client
1056                    .get(&url)
1057                    .header("Authorization", format!("token {}", self.token))
1058                    .send()
1059                    .await?;
1060                if !response.status().is_success() {
1061                    let status = response.status();
1062                    let error_text = response.text().await?;
1063                    return Err(DWaveError::ApiError(format!(
1064                        "Error getting problem status: {} - {}",
1065                        status, error_text
1066                    )));
1067                }
1068                let problem_info: ProblemInfo = response.json().await?;
1069                Ok(problem_info)
1070            })
1071        }
1072        /// Cancel a running problem
1073        pub fn cancel_problem(&self, problem_id: &str) -> DWaveResult<()> {
1074            let url = format!("{}/problems/{}/cancel", self.endpoint, problem_id);
1075            self.runtime.block_on(async {
1076                let response = self
1077                    .client
1078                    .delete(&url)
1079                    .header("Authorization", format!("token {}", self.token))
1080                    .send()
1081                    .await?;
1082                if !response.status().is_success() {
1083                    let status = response.status();
1084                    let error_text = response.text().await?;
1085                    return Err(DWaveError::ApiError(format!(
1086                        "Error cancelling problem: {} - {}",
1087                        status, error_text
1088                    )));
1089                }
1090                Ok(())
1091            })
1092        }
1093        /// Submit multiple problems in batch
1094        pub fn submit_batch(
1095            &self,
1096            problems: Vec<(&IsingModel, Option<&str>, Option<AdvancedProblemParams>)>,
1097        ) -> DWaveResult<BatchSubmissionResult> {
1098            let start_time = Instant::now();
1099            let mut problem_ids = Vec::new();
1100            let mut statuses = Vec::new();
1101            for (model, solver_id, params) in problems {
1102                match self.submit_ising_with_embedding(model, solver_id, params, None) {
1103                    Ok(solution) => {
1104                        problem_ids.push(solution.problem_id.clone());
1105                        statuses.push(Ok(solution.problem_id));
1106                    }
1107                    Err(e) => {
1108                        problem_ids.push(String::new());
1109                        statuses.push(Err(e));
1110                    }
1111                }
1112            }
1113            Ok(BatchSubmissionResult {
1114                problem_ids,
1115                statuses,
1116                submission_time: start_time.elapsed(),
1117            })
1118        }
1119        /// Get performance metrics for a completed problem
1120        pub fn get_problem_metrics(&self, problem_id: &str) -> DWaveResult<ProblemMetrics> {
1121            let solution = self.get_problem_result(problem_id)?;
1122            let timing = &solution.timing;
1123            let queue_time =
1124                Duration::from_micros(timing["qpu_access_overhead_time"].as_u64().unwrap_or(0));
1125            let programming_time =
1126                Duration::from_micros(timing["qpu_programming_time"].as_u64().unwrap_or(0));
1127            let sampling_time =
1128                Duration::from_micros(timing["qpu_sampling_time"].as_u64().unwrap_or(0));
1129            let readout_time =
1130                Duration::from_micros(timing["qpu_readout_time"].as_u64().unwrap_or(0));
1131            let total_time = queue_time + programming_time + sampling_time + readout_time;
1132            let access_time = programming_time + sampling_time + readout_time;
1133            let best_energy = solution
1134                .energies
1135                .iter()
1136                .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
1137                .copied()
1138                .unwrap_or(f64::INFINITY);
1139            Ok(ProblemMetrics {
1140                total_time,
1141                queue_time,
1142                access_time,
1143                programming_time,
1144                sampling_time,
1145                readout_time,
1146                best_energy,
1147                num_valid_solutions: solution.solutions.len(),
1148                chain_break_fraction: timing["chain_break_fraction"].as_f64(),
1149            })
1150        }
1151        /// Get problem result (blocking until completion)
1152        pub fn get_problem_result(&self, problem_id: &str) -> DWaveResult<Solution> {
1153            let start_time = Instant::now();
1154            loop {
1155                let status = self.get_problem_status(problem_id)?;
1156                match status.status {
1157                    ProblemStatus::Completed => {
1158                        return self.get_solution_data(problem_id);
1159                    }
1160                    ProblemStatus::Failed => {
1161                        return Err(DWaveError::StatusError(format!(
1162                            "Problem {} failed",
1163                            problem_id
1164                        )));
1165                    }
1166                    ProblemStatus::Cancelled => {
1167                        return Err(DWaveError::StatusError(format!(
1168                            "Problem {} was cancelled",
1169                            problem_id
1170                        )));
1171                    }
1172                    ProblemStatus::InProgress | ProblemStatus::Pending => {
1173                        if start_time.elapsed() > self.problem_timeout {
1174                            return Err(DWaveError::TimeoutError(format!(
1175                                "Timeout waiting for problem {} completion",
1176                                problem_id
1177                            )));
1178                        }
1179                        std::thread::sleep(Duration::from_secs(2));
1180                    }
1181                }
1182            }
1183        }
1184        /// Get solution data for a completed problem
1185        fn get_solution_data(&self, problem_id: &str) -> DWaveResult<Solution> {
1186            let url = format!("{}/problems/{}", self.endpoint, problem_id);
1187            self.runtime.block_on(async {
1188                let response = self
1189                    .client
1190                    .get(&url)
1191                    .header("Authorization", format!("token {}", self.token))
1192                    .send()
1193                    .await?;
1194                if !response.status().is_success() {
1195                    let status = response.status();
1196                    let error_text = response.text().await?;
1197                    return Err(DWaveError::ApiError(format!(
1198                        "Error getting solution data: {} - {}",
1199                        status, error_text
1200                    )));
1201                }
1202                let data: serde_json::Value = response.json().await?;
1203                Ok(Solution {
1204                    energies: serde_json::from_value(data["energies"].clone())?,
1205                    occurrences: serde_json::from_value(data["occurrences"].clone())?,
1206                    solutions: serde_json::from_value(data["solutions"].clone())?,
1207                    num_samples: data["num_samples"].as_u64().unwrap_or(0) as usize,
1208                    problem_id: problem_id.to_string(),
1209                    solver: data["solver"].as_str().unwrap_or("unknown").to_string(),
1210                    timing: data["timing"].clone(),
1211                })
1212            })
1213        }
1214        /// List recent problems
1215        pub fn list_problems(&self, limit: Option<usize>) -> DWaveResult<Vec<ProblemInfo>> {
1216            let mut url = format!("{}/problems", self.endpoint);
1217            if let Some(limit) = limit {
1218                let _ = write!(url, "?limit={}", limit);
1219            }
1220            self.runtime.block_on(async {
1221                let response = self
1222                    .client
1223                    .get(&url)
1224                    .header("Authorization", format!("token {}", self.token))
1225                    .send()
1226                    .await?;
1227                if !response.status().is_success() {
1228                    let status = response.status();
1229                    let error_text = response.text().await?;
1230                    return Err(DWaveError::ApiError(format!(
1231                        "Error listing problems: {} - {}",
1232                        status, error_text
1233                    )));
1234                }
1235                let problems: Vec<ProblemInfo> = response.json().await?;
1236                Ok(problems)
1237            })
1238        }
1239        /// Get account usage information
1240        pub fn get_usage_info(&self) -> DWaveResult<serde_json::Value> {
1241            let url = format!("{}/usage", self.endpoint);
1242            self.runtime.block_on(async {
1243                let response = self
1244                    .client
1245                    .get(&url)
1246                    .header("Authorization", format!("token {}", self.token))
1247                    .send()
1248                    .await?;
1249                if !response.status().is_success() {
1250                    let status = response.status();
1251                    let error_text = response.text().await?;
1252                    return Err(DWaveError::ApiError(format!(
1253                        "Error getting usage info: {} - {}",
1254                        status, error_text
1255                    )));
1256                }
1257                let usage: serde_json::Value = response.json().await?;
1258                Ok(usage)
1259            })
1260        }
1261    }
1262}
1263#[cfg(not(feature = "dwave"))]
1264mod placeholder {
1265    use thiserror::Error;
1266    /// Error type for when D-Wave feature is not enabled
1267    #[derive(Error, Debug)]
1268    pub enum DWaveError {
1269        /// Error when trying to use D-Wave without the feature enabled
1270        #[error("D-Wave feature not enabled. Recompile with '--features dwave'")]
1271        NotEnabled,
1272    }
1273    /// Result type for D-Wave operations
1274    pub type DWaveResult<T> = Result<T, DWaveError>;
1275    /// Placeholder for D-Wave client
1276    #[derive(Debug, Clone)]
1277    pub struct DWaveClient {
1278        _private: (),
1279    }
1280    impl DWaveClient {
1281        /// Placeholder for D-Wave client creation
1282        pub fn new(_token: impl Into<String>, _endpoint: Option<String>) -> DWaveResult<Self> {
1283            Err(DWaveError::NotEnabled)
1284        }
1285    }
1286    /// Placeholder for D-Wave problem submission parameters
1287    #[derive(Debug, Clone)]
1288    pub struct ProblemParams {
1289        /// Number of reads/samples to take
1290        pub num_reads: usize,
1291        /// Annealing time in microseconds
1292        pub annealing_time: usize,
1293        /// Programming thermalization in microseconds
1294        pub programming_therm: usize,
1295        /// Read-out thermalization in microseconds
1296        pub readout_therm: usize,
1297    }
1298    /// Placeholder types for enhanced Leap functionality (feature disabled)
1299    #[derive(Debug, Clone)]
1300    pub enum SolverType {
1301        QuantumProcessor,
1302        Hybrid,
1303        Software,
1304    }
1305    #[derive(Debug, Clone)]
1306    pub enum SolverCategory {
1307        QPU,
1308        Hybrid,
1309        Software,
1310        All,
1311    }
1312    #[derive(Debug, Clone)]
1313    pub enum ProblemStatus {
1314        InProgress,
1315        Completed,
1316        Failed,
1317        Cancelled,
1318        Pending,
1319    }
1320    #[derive(Debug, Clone)]
1321    pub struct SolverSelector;
1322    #[derive(Debug, Clone)]
1323    pub struct EmbeddingConfig;
1324    #[derive(Debug, Clone)]
1325    pub struct AdvancedProblemParams;
1326    #[derive(Debug, Clone)]
1327    pub struct HybridSolverParams;
1328    #[derive(Debug, Clone)]
1329    pub struct LeapSolverInfo;
1330    #[derive(Debug, Clone)]
1331    pub struct ProblemInfo;
1332    #[derive(Debug, Clone)]
1333    pub struct AnnealingSchedule;
1334    #[derive(Debug, Clone)]
1335    pub struct ProblemMetrics;
1336    #[derive(Debug, Clone)]
1337    pub struct BatchSubmissionResult;
1338    #[derive(Debug, Clone)]
1339    pub enum ChainStrengthMethod {
1340        Auto,
1341        Fixed(f64),
1342        Adaptive(f64),
1343    }
1344    impl Default for ProblemParams {
1345        fn default() -> Self {
1346            Self {
1347                num_reads: 1000,
1348                annealing_time: 20,
1349                programming_therm: 1000,
1350                readout_therm: 0,
1351            }
1352        }
1353    }
1354}
1355/// Check if D-Wave API support is enabled
1356#[must_use]
1357pub const fn is_available() -> bool {
1358    cfg!(feature = "dwave")
1359}