1#[cfg(feature = "braket")]
20mod client {
21 use reqwest::Client;
22 use serde::{Deserialize, Serialize};
23 use std::collections::HashMap;
24 use std::fmt::Write;
25 use std::time::{Duration, Instant};
26 use thiserror::Error;
27 use tokio::runtime::Runtime;
28
29 use crate::ising::{IsingError, IsingModel, QuboModel};
30
31 #[derive(Error, Debug)]
33 pub enum BraketError {
34 #[error("Ising error: {0}")]
36 IsingError(#[from] IsingError),
37
38 #[error("Network error: {0}")]
40 NetworkError(#[from] reqwest::Error),
41
42 #[error("Response parsing error: {0}")]
44 ParseError(#[from] serde_json::Error),
45
46 #[error("AWS Braket API error: {0}")]
48 ApiError(String),
49
50 #[error("Authentication error: {0}")]
52 AuthError(String),
53
54 #[error("Runtime error: {0}")]
56 RuntimeError(String),
57
58 #[error("Problem formulation error: {0}")]
60 ProblemError(String),
61
62 #[error("Quantum task error: {0}")]
64 TaskError(String),
65
66 #[error("Device configuration error: {0}")]
68 DeviceConfigError(String),
69
70 #[error("Batch operation error: {0}")]
72 BatchError(String),
73
74 #[error("Operation timed out: {0}")]
76 TimeoutError(String),
77
78 #[error("Cost limit exceeded: {0}")]
80 CostLimitError(String),
81
82 #[error("AWS SDK error: {0}")]
84 AwsSdkError(String),
85 }
86
87 pub type BraketResult<T> = Result<T, BraketError>;
89
90 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92 pub enum DeviceType {
93 #[serde(rename = "QPU")]
95 QuantumProcessor,
96 #[serde(rename = "SIMULATOR")]
98 Simulator,
99 }
100
101 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
103 pub enum DeviceStatus {
104 #[serde(rename = "ONLINE")]
106 Online,
107 #[serde(rename = "OFFLINE")]
109 Offline,
110 #[serde(rename = "RETIRED")]
112 Retired,
113 }
114
115 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
117 pub enum TaskStatus {
118 #[serde(rename = "RUNNING")]
120 Running,
121 #[serde(rename = "COMPLETED")]
123 Completed,
124 #[serde(rename = "FAILED")]
126 Failed,
127 #[serde(rename = "CANCELLED")]
129 Cancelled,
130 #[serde(rename = "QUEUED")]
132 Queued,
133 #[serde(rename = "CREATED")]
135 Created,
136 }
137
138 #[derive(Debug, Clone, Serialize, Deserialize)]
140 pub struct BraketDevice {
141 pub device_arn: String,
143 pub device_name: String,
145 pub provider_name: String,
147 pub device_type: DeviceType,
149 pub device_status: DeviceStatus,
151 pub device_capabilities: serde_json::Value,
153 pub device_parameters: Option<serde_json::Value>,
155 }
156
157 #[derive(Debug, Clone, Serialize, Deserialize)]
159 pub struct AnnealingProblem {
160 #[serde(rename = "type")]
162 pub problem_type: String,
163 pub linear: HashMap<String, f64>,
165 pub quadratic: HashMap<String, f64>,
167 pub shots: usize,
169 }
170
171 #[derive(Debug, Clone, Serialize, Deserialize)]
173 pub struct AnalogHamiltonianSimulation {
174 pub hamiltonian: serde_json::Value,
176 pub time: f64,
178 pub steps: Option<usize>,
180 }
181
182 #[derive(Debug, Clone, Serialize, Deserialize)]
184 pub struct TaskParams {
185 pub device_arn: String,
187 pub shots: usize,
189 #[serde(flatten)]
191 pub device_parameters: HashMap<String, serde_json::Value>,
192 }
193
194 impl Default for TaskParams {
195 fn default() -> Self {
196 Self {
197 device_arn: String::new(),
198 shots: 1000,
199 device_parameters: HashMap::new(),
200 }
201 }
202 }
203
204 #[derive(Debug, Clone, Serialize, Deserialize)]
206 pub struct TaskResult {
207 pub task_arn: String,
209 pub task_status: TaskStatus,
211 pub result: Option<serde_json::Value>,
213 pub measurements: Option<Vec<HashMap<String, i32>>>,
215 pub measurement_counts: Option<HashMap<String, usize>>,
217 pub task_metadata: serde_json::Value,
219 pub additional_metadata: Option<serde_json::Value>,
221 }
222
223 #[derive(Debug, Clone)]
225 pub struct DeviceSelector {
226 pub device_type: Option<DeviceType>,
228 pub provider: Option<String>,
230 pub status: DeviceStatus,
232 pub min_fidelity: Option<f64>,
234 pub max_cost_per_shot: Option<f64>,
236 pub required_capabilities: Vec<String>,
238 }
239
240 impl Default for DeviceSelector {
241 fn default() -> Self {
242 Self {
243 device_type: None,
244 provider: None,
245 status: DeviceStatus::Online,
246 min_fidelity: None,
247 max_cost_per_shot: None,
248 required_capabilities: Vec::new(),
249 }
250 }
251 }
252
253 #[derive(Debug, Clone, Serialize, Deserialize)]
255 pub struct AdvancedAnnealingParams {
256 pub shots: usize,
258 pub annealing_time: Option<f64>,
260 pub programming_thermalization: Option<f64>,
262 pub readout_thermalization: Option<f64>,
264 pub beta_schedule: Option<Vec<(f64, f64)>>,
266 pub s_schedule: Option<Vec<(f64, f64)>>,
268 pub auto_scale: Option<bool>,
270 pub flux_biases: Option<HashMap<String, f64>>,
272 #[serde(flatten)]
274 pub extra: HashMap<String, serde_json::Value>,
275 }
276
277 impl Default for AdvancedAnnealingParams {
278 fn default() -> Self {
279 Self {
280 shots: 1000,
281 annealing_time: Some(20.0),
282 programming_thermalization: Some(1000.0),
283 readout_thermalization: Some(100.0),
284 beta_schedule: None,
285 s_schedule: None,
286 auto_scale: Some(true),
287 flux_biases: None,
288 extra: HashMap::new(),
289 }
290 }
291 }
292
293 #[derive(Debug, Clone)]
295 pub struct TaskMetrics {
296 pub total_time: Duration,
298 pub queue_time: Duration,
300 pub execution_time: Duration,
302 pub cost: f64,
304 pub success_rate: f64,
306 pub average_energy: Option<f64>,
308 pub best_energy: Option<f64>,
310 pub energy_std: Option<f64>,
312 }
313
314 #[derive(Debug)]
316 pub struct BatchTaskResult {
317 pub task_arns: Vec<String>,
319 pub statuses: Vec<Result<String, BraketError>>,
321 pub submission_time: Duration,
323 pub estimated_cost: f64,
325 }
326
327 #[derive(Debug, Clone)]
329 pub struct CostTracker {
330 pub cost_limit: Option<f64>,
332 pub current_cost: f64,
334 pub cost_estimates: HashMap<String, f64>,
336 }
337
338 impl Default for CostTracker {
339 fn default() -> Self {
340 Self {
341 cost_limit: None,
342 current_cost: 0.0,
343 cost_estimates: HashMap::new(),
344 }
345 }
346 }
347
348 #[derive(Debug)]
350 pub struct BraketClient {
351 client: Client,
353
354 region: String,
356
357 credentials: (String, String, Option<String>),
359
360 runtime: Runtime,
362
363 default_device_selector: DeviceSelector,
365
366 cost_tracker: CostTracker,
368
369 max_retries: usize,
371
372 request_timeout: Duration,
374
375 task_timeout: Duration,
377 }
378
379 impl BraketClient {
380 pub fn new(
382 access_key: impl Into<String>,
383 secret_key: impl Into<String>,
384 region: impl Into<String>,
385 ) -> BraketResult<Self> {
386 Self::with_config(
387 access_key,
388 secret_key,
389 None,
390 region,
391 DeviceSelector::default(),
392 CostTracker::default(),
393 )
394 }
395
396 pub fn with_config(
398 access_key: impl Into<String>,
399 secret_key: impl Into<String>,
400 session_token: Option<String>,
401 region: impl Into<String>,
402 device_selector: DeviceSelector,
403 cost_tracker: CostTracker,
404 ) -> BraketResult<Self> {
405 let client = Client::builder()
407 .timeout(Duration::from_secs(300))
408 .build()
409 .map_err(BraketError::NetworkError)?;
410
411 let runtime = Runtime::new().map_err(|e| BraketError::RuntimeError(e.to_string()))?;
413
414 Ok(Self {
415 client,
416 region: region.into(),
417 credentials: (access_key.into(), secret_key.into(), session_token),
418 runtime,
419 default_device_selector: device_selector,
420 cost_tracker,
421 max_retries: 3,
422 request_timeout: Duration::from_secs(300),
423 task_timeout: Duration::from_secs(1800), })
425 }
426
427 pub fn get_devices(&self) -> BraketResult<Vec<BraketDevice>> {
429 let url = format!("https://braket.{}.amazonaws.com/devices", self.region);
430
431 self.runtime.block_on(async {
432 let response = self
433 .client
434 .get(&url)
435 .header("Authorization", self.get_auth_header().await?)
436 .send()
437 .await?;
438
439 if !response.status().is_success() {
440 let status = response.status();
441 let error_text = response.text().await?;
442 return Err(BraketError::ApiError(format!(
443 "Error getting devices: {} - {}",
444 status, error_text
445 )));
446 }
447
448 let devices_response: serde_json::Value = response.json().await?;
449 let devices: Vec<BraketDevice> =
450 serde_json::from_value(devices_response["devices"].clone())?;
451 Ok(devices)
452 })
453 }
454
455 pub fn select_device(
457 &self,
458 selector: Option<&DeviceSelector>,
459 ) -> BraketResult<BraketDevice> {
460 let selector = selector.unwrap_or(&self.default_device_selector);
461 let devices = self.get_devices()?;
462
463 let filtered_devices: Vec<_> = devices
464 .into_iter()
465 .filter(|device| {
466 let type_match = selector
468 .device_type
469 .as_ref()
470 .map(|dt| &device.device_type == dt)
471 .unwrap_or(true);
472
473 let provider_match = selector
475 .provider
476 .as_ref()
477 .map(|p| device.provider_name.contains(p))
478 .unwrap_or(true);
479
480 let status_match = device.device_status == selector.status;
482
483 type_match && provider_match && status_match
484 })
485 .collect();
486
487 if filtered_devices.is_empty() {
488 return Err(BraketError::DeviceConfigError(
489 "No devices match the selection criteria".to_string(),
490 ));
491 }
492
493 let mut best_device = filtered_devices[0].clone();
495 for device in &filtered_devices[1..] {
496 if matches!(device.device_type, DeviceType::QuantumProcessor)
497 && matches!(best_device.device_type, DeviceType::Simulator)
498 {
499 best_device = device.clone();
500 }
501 }
502
503 Ok(best_device)
504 }
505
506 pub fn submit_ising(
508 &self,
509 model: &IsingModel,
510 device_arn: Option<&str>,
511 params: Option<AdvancedAnnealingParams>,
512 ) -> BraketResult<TaskResult> {
513 let params = params.unwrap_or_default();
514
515 let device = if let Some(arn) = device_arn {
517 self.get_device_by_arn(arn)?
518 } else {
519 let annealing_selector = DeviceSelector {
520 device_type: Some(DeviceType::QuantumProcessor),
521 required_capabilities: vec!["ANNEALING".to_string()],
522 ..Default::default()
523 };
524 self.select_device(Some(&annealing_selector))?
525 };
526
527 let estimated_cost = self.estimate_task_cost(&device, params.shots);
529 self.check_cost_limit(estimated_cost)?;
530
531 let mut linear = HashMap::new();
533 for (qubit, bias) in model.biases() {
534 linear.insert(qubit.to_string(), bias);
535 }
536
537 let mut quadratic = HashMap::new();
538 for coupling in model.couplings() {
539 let key = format!("({},{})", coupling.i, coupling.j);
540 quadratic.insert(key, coupling.strength);
541 }
542
543 let problem = AnnealingProblem {
544 problem_type: "ising".to_string(),
545 linear,
546 quadratic,
547 shots: params.shots,
548 };
549
550 self.submit_annealing_task(&device, &problem, ¶ms)
552 }
553
554 pub fn submit_qubo(
556 &self,
557 model: &QuboModel,
558 device_arn: Option<&str>,
559 params: Option<AdvancedAnnealingParams>,
560 ) -> BraketResult<TaskResult> {
561 let params = params.unwrap_or_default();
562
563 let device = if let Some(arn) = device_arn {
565 self.get_device_by_arn(arn)?
566 } else {
567 let annealing_selector = DeviceSelector {
568 device_type: Some(DeviceType::QuantumProcessor),
569 required_capabilities: vec!["ANNEALING".to_string()],
570 ..Default::default()
571 };
572 self.select_device(Some(&annealing_selector))?
573 };
574
575 let estimated_cost = self.estimate_task_cost(&device, params.shots);
577 self.check_cost_limit(estimated_cost)?;
578
579 let mut linear = HashMap::new();
581 for (var, value) in model.linear_terms() {
582 linear.insert(var.to_string(), value);
583 }
584
585 let mut quadratic = HashMap::new();
586 for (var1, var2, value) in model.quadratic_terms() {
587 let key = format!("({},{})", var1, var2);
588 quadratic.insert(key, value);
589 }
590
591 let problem = AnnealingProblem {
592 problem_type: "qubo".to_string(),
593 linear,
594 quadratic,
595 shots: params.shots,
596 };
597
598 self.submit_annealing_task(&device, &problem, ¶ms)
600 }
601
602 pub fn submit_batch(
604 &self,
605 tasks: Vec<(&IsingModel, Option<&str>, Option<AdvancedAnnealingParams>)>,
606 ) -> BraketResult<BatchTaskResult> {
607 let start_time = Instant::now();
608 let mut task_arns = Vec::new();
609 let mut statuses = Vec::new();
610 let mut total_cost = 0.0;
611
612 for (model, device_arn, params) in tasks {
613 match self.submit_ising(model, device_arn, params.clone()) {
614 Ok(task_result) => {
615 task_arns.push(task_result.task_arn.clone());
616 statuses.push(Ok(task_result.task_arn));
617 if let Some(params) = ¶ms {
619 total_cost += self.estimate_shot_cost(device_arn, params.shots);
620 }
621 }
622 Err(e) => {
623 task_arns.push(String::new());
624 statuses.push(Err(e));
625 }
626 }
627 }
628
629 Ok(BatchTaskResult {
630 task_arns,
631 statuses,
632 submission_time: start_time.elapsed(),
633 estimated_cost: total_cost,
634 })
635 }
636
637 pub fn get_task_status(&self, task_arn: &str) -> BraketResult<TaskResult> {
639 let url = format!(
640 "https://braket.{}.amazonaws.com/quantum-task/{}",
641 self.region, task_arn
642 );
643
644 self.runtime.block_on(async {
645 let response = self
646 .client
647 .get(&url)
648 .header("Authorization", self.get_auth_header().await?)
649 .send()
650 .await?;
651
652 if !response.status().is_success() {
653 let status = response.status();
654 let error_text = response.text().await?;
655 return Err(BraketError::ApiError(format!(
656 "Error getting task status: {} - {}",
657 status, error_text
658 )));
659 }
660
661 let task_result: TaskResult = response.json().await?;
662 Ok(task_result)
663 })
664 }
665
666 pub fn cancel_task(&self, task_arn: &str) -> BraketResult<()> {
668 let url = format!(
669 "https://braket.{}.amazonaws.com/quantum-task/{}/cancel",
670 self.region, task_arn
671 );
672
673 self.runtime.block_on(async {
674 let response = self
675 .client
676 .post(&url)
677 .header("Authorization", self.get_auth_header().await?)
678 .send()
679 .await?;
680
681 if !response.status().is_success() {
682 let status = response.status();
683 let error_text = response.text().await?;
684 return Err(BraketError::ApiError(format!(
685 "Error cancelling task: {} - {}",
686 status, error_text
687 )));
688 }
689
690 Ok(())
691 })
692 }
693
694 pub fn get_task_result(&self, task_arn: &str) -> BraketResult<TaskResult> {
696 let start_time = Instant::now();
697
698 loop {
699 let task_result = self.get_task_status(task_arn)?;
700
701 match task_result.task_status {
702 TaskStatus::Completed => {
703 return Ok(task_result);
704 }
705 TaskStatus::Failed => {
706 return Err(BraketError::TaskError(format!("Task {} failed", task_arn)));
707 }
708 TaskStatus::Cancelled => {
709 return Err(BraketError::TaskError(format!(
710 "Task {} was cancelled",
711 task_arn
712 )));
713 }
714 TaskStatus::Running | TaskStatus::Queued | TaskStatus::Created => {
715 if start_time.elapsed() > self.task_timeout {
716 return Err(BraketError::TimeoutError(format!(
717 "Timeout waiting for task {} completion",
718 task_arn
719 )));
720 }
721 std::thread::sleep(Duration::from_secs(5));
723 }
724 }
725 }
726 }
727
728 pub fn get_task_metrics(&self, task_arn: &str) -> BraketResult<TaskMetrics> {
730 let task_result = self.get_task_result(task_arn)?;
731
732 let metadata = &task_result.task_metadata;
734
735 let queue_time = Duration::from_secs(metadata["queueTime"].as_u64().unwrap_or(0));
736 let execution_time =
737 Duration::from_secs(metadata["executionTime"].as_u64().unwrap_or(0));
738 let total_time = queue_time + execution_time;
739
740 let cost = metadata["cost"].as_f64().unwrap_or(0.0);
741 let success_rate = metadata["successRate"].as_f64().unwrap_or(1.0);
742
743 let (average_energy, best_energy, energy_std) =
745 if let Some(measurements) = &task_result.measurements {
746 let energies: Vec<f64> = measurements
747 .iter()
748 .filter_map(|m| m.get("energy").and_then(|e| Some(*e as f64)))
749 .collect();
750
751 if !energies.is_empty() {
752 let avg = energies.iter().sum::<f64>() / energies.len() as f64;
753 let best = energies.iter().fold(f64::INFINITY, |a, &b| a.min(b));
754 let variance = energies.iter().map(|&e| (e - avg).powi(2)).sum::<f64>()
755 / energies.len() as f64;
756 let std_dev = variance.sqrt();
757
758 (Some(avg), Some(best), Some(std_dev))
759 } else {
760 (None, None, None)
761 }
762 } else {
763 (None, None, None)
764 };
765
766 Ok(TaskMetrics {
767 total_time,
768 queue_time,
769 execution_time,
770 cost,
771 success_rate,
772 average_energy,
773 best_energy,
774 energy_std,
775 })
776 }
777
778 pub fn list_tasks(&self, limit: Option<usize>) -> BraketResult<Vec<TaskResult>> {
780 let mut url = format!("https://braket.{}.amazonaws.com/quantum-tasks", self.region);
781 if let Some(limit) = limit {
782 let _ = write!(url, "?limit={}", limit);
783 }
784
785 self.runtime.block_on(async {
786 let response = self
787 .client
788 .get(&url)
789 .header("Authorization", self.get_auth_header().await?)
790 .send()
791 .await?;
792
793 if !response.status().is_success() {
794 let status = response.status();
795 let error_text = response.text().await?;
796 return Err(BraketError::ApiError(format!(
797 "Error listing tasks: {} - {}",
798 status, error_text
799 )));
800 }
801
802 let tasks_response: serde_json::Value = response.json().await?;
803 let tasks: Vec<TaskResult> =
804 serde_json::from_value(tasks_response["quantumTasks"].clone())?;
805 Ok(tasks)
806 })
807 }
808
809 pub fn get_cost_summary(&self) -> BraketResult<serde_json::Value> {
811 let url = format!("https://braket.{}.amazonaws.com/usage", self.region);
812
813 self.runtime.block_on(async {
814 let response = self
815 .client
816 .get(&url)
817 .header("Authorization", self.get_auth_header().await?)
818 .send()
819 .await?;
820
821 if !response.status().is_success() {
822 let status = response.status();
823 let error_text = response.text().await?;
824 return Err(BraketError::ApiError(format!(
825 "Error getting cost summary: {} - {}",
826 status, error_text
827 )));
828 }
829
830 let usage: serde_json::Value = response.json().await?;
831 Ok(usage)
832 })
833 }
834
835 fn submit_annealing_task(
839 &self,
840 device: &BraketDevice,
841 problem: &AnnealingProblem,
842 params: &AdvancedAnnealingParams,
843 ) -> BraketResult<TaskResult> {
844 let url = format!("https://braket.{}.amazonaws.com/quantum-task", self.region);
845
846 let mut task_spec = serde_json::json!({
848 "deviceArn": device.device_arn,
849 "action": {
850 "type": "braket.ir.annealing.Problem",
851 "linear": problem.linear,
852 "quadratic": problem.quadratic
853 },
854 "shots": params.shots
855 });
856
857 if let Some(annealing_time) = params.annealing_time {
859 task_spec["deviceParameters"]["annealingTime"] = serde_json::json!(annealing_time);
860 }
861 if let Some(prog_therm) = params.programming_thermalization {
862 task_spec["deviceParameters"]["programmingThermalization"] =
863 serde_json::json!(prog_therm);
864 }
865 if let Some(readout_therm) = params.readout_thermalization {
866 task_spec["deviceParameters"]["readoutThermalization"] =
867 serde_json::json!(readout_therm);
868 }
869
870 self.runtime.block_on(async {
871 let response = self
872 .client
873 .post(&url)
874 .header("Authorization", self.get_auth_header().await?)
875 .header("Content-Type", "application/json")
876 .json(&task_spec)
877 .send()
878 .await?;
879
880 if !response.status().is_success() {
881 let status = response.status();
882 let error_text = response.text().await?;
883 return Err(BraketError::ApiError(format!(
884 "Error submitting task: {} - {}",
885 status, error_text
886 )));
887 }
888
889 let task_result: TaskResult = response.json().await?;
890 Ok(task_result)
891 })
892 }
893
894 fn get_device_by_arn(&self, arn: &str) -> BraketResult<BraketDevice> {
896 let devices = self.get_devices()?;
897 devices
898 .into_iter()
899 .find(|d| d.device_arn == arn)
900 .ok_or_else(|| BraketError::DeviceConfigError(format!("Device {} not found", arn)))
901 }
902
903 fn estimate_task_cost(&self, device: &BraketDevice, shots: usize) -> f64 {
905 let base_cost = match device.device_type {
907 DeviceType::QuantumProcessor => {
908 if device.provider_name.contains("IonQ") {
909 0.01 } else if device.provider_name.contains("Rigetti") {
911 0.00_035 } else {
913 0.001 }
915 }
916 DeviceType::Simulator => 0.0, };
918
919 base_cost * shots as f64
920 }
921
922 fn estimate_shot_cost(&self, device_arn: Option<&str>, shots: usize) -> f64 {
924 if let Some(arn) = device_arn {
925 if let Ok(device) = self.get_device_by_arn(arn) {
926 return self.estimate_task_cost(&device, shots);
927 }
928 }
929 0.001 * shots as f64
931 }
932
933 fn check_cost_limit(&self, estimated_cost: f64) -> BraketResult<()> {
935 if let Some(limit) = self.cost_tracker.cost_limit {
936 if self.cost_tracker.current_cost + estimated_cost > limit {
937 return Err(BraketError::CostLimitError(format!(
938 "Estimated cost ${:.4} would exceed limit ${:.4}",
939 estimated_cost, limit
940 )));
941 }
942 }
943 Ok(())
944 }
945
946 async fn get_auth_header(&self) -> BraketResult<String> {
948 Ok(format!(
951 "AWS4-HMAC-SHA256 Credential={}/...",
952 self.credentials.0
953 ))
954 }
955 }
956}
957
958#[cfg(feature = "braket")]
959pub use client::*;
960
961#[cfg(not(feature = "braket"))]
962mod placeholder {
963 use thiserror::Error;
964
965 #[derive(Error, Debug)]
967 pub enum BraketError {
968 #[error("AWS Braket feature not enabled. Recompile with '--features braket'")]
970 NotEnabled,
971 }
972
973 pub type BraketResult<T> = Result<T, BraketError>;
975
976 #[derive(Debug, Clone)]
978 pub struct BraketClient {
979 _private: (),
980 }
981
982 impl BraketClient {
983 pub fn new(
985 _access_key: impl Into<String>,
986 _secret_key: impl Into<String>,
987 _region: impl Into<String>,
988 ) -> BraketResult<Self> {
989 Err(BraketError::NotEnabled)
990 }
991 }
992
993 #[derive(Debug, Clone)]
995 pub enum DeviceType {
996 QuantumProcessor,
997 Simulator,
998 }
999
1000 #[derive(Debug, Clone)]
1001 pub enum DeviceStatus {
1002 Online,
1003 Offline,
1004 Retired,
1005 }
1006
1007 #[derive(Debug, Clone)]
1008 pub enum TaskStatus {
1009 Running,
1010 Completed,
1011 Failed,
1012 Cancelled,
1013 Queued,
1014 Created,
1015 }
1016
1017 #[derive(Debug, Clone)]
1018 pub struct BraketDevice;
1019
1020 #[derive(Debug, Clone)]
1021 pub struct DeviceSelector;
1022
1023 #[derive(Debug, Clone)]
1024 pub struct AdvancedAnnealingParams;
1025
1026 #[derive(Debug, Clone)]
1027 pub struct TaskResult;
1028
1029 #[derive(Debug, Clone)]
1030 pub struct TaskMetrics;
1031
1032 #[derive(Debug, Clone)]
1033 pub struct BatchTaskResult;
1034
1035 #[derive(Debug, Clone)]
1036 pub struct CostTracker;
1037
1038 impl Default for DeviceSelector {
1039 fn default() -> Self {
1040 Self
1041 }
1042 }
1043
1044 impl Default for AdvancedAnnealingParams {
1045 fn default() -> Self {
1046 Self
1047 }
1048 }
1049
1050 impl Default for CostTracker {
1051 fn default() -> Self {
1052 Self
1053 }
1054 }
1055}
1056
1057#[cfg(not(feature = "braket"))]
1058pub use placeholder::*;
1059
1060#[must_use]
1062pub const fn is_available() -> bool {
1063 cfg!(feature = "braket")
1064}
1065
1066use std::fmt::Write;