quantrs2_tytan/sampler/hardware/
fujitsu.rs1use crate::sampler::{SampleResult, Sampler, SamplerError, SamplerResult};
7use scirs2_core::ndarray::Array2;
8use std::collections::HashMap;
9use std::time::Duration;
10
11#[derive(Debug, Clone)]
13pub struct FujitsuConfig {
14 pub endpoint: String,
16 pub api_key: String,
18 pub annealing_time: u32,
20 pub num_replicas: u32,
22 pub offset_increment: f64,
24 pub temperature_start: f64,
26 pub temperature_end: f64,
28 pub temperature_mode: TemperatureMode,
30}
31
32#[derive(Debug, Clone)]
33pub enum TemperatureMode {
34 Linear,
36 Exponential,
38 Adaptive,
40}
41
42impl Default for FujitsuConfig {
43 fn default() -> Self {
44 Self {
45 endpoint: "https://api.da.fujitsu.com/v2".to_string(),
46 api_key: String::new(),
47 annealing_time: 1000,
48 num_replicas: 16,
49 offset_increment: 100.0,
50 temperature_start: 1000.0,
51 temperature_end: 0.1,
52 temperature_mode: TemperatureMode::Exponential,
53 }
54 }
55}
56
57pub struct FujitsuDigitalAnnealerSampler {
59 config: FujitsuConfig,
60 max_variables: usize,
62 connectivity: ConnectivityType,
64}
65
66#[derive(Debug, Clone)]
67pub enum ConnectivityType {
68 FullyConnected,
70 KingsGraph,
72 Chimera { unit_size: usize },
74}
75
76impl FujitsuDigitalAnnealerSampler {
77 pub const fn new(config: FujitsuConfig) -> Self {
79 Self {
80 config,
81 max_variables: 8192, connectivity: ConnectivityType::FullyConnected,
83 }
84 }
85
86 pub const fn with_connectivity(mut self, connectivity: ConnectivityType) -> Self {
88 self.connectivity = connectivity;
89 self
90 }
91
92 fn submit_problem(&self, _qubo: &Array2<f64>) -> Result<String, SamplerError> {
94 Ok("job_12345".to_string())
101 }
102
103 fn get_results(
105 &self,
106 _job_id: &str,
107 _timeout: Duration,
108 ) -> Result<Vec<DASolution>, SamplerError> {
109 Ok(vec![DASolution {
116 configuration: vec![0; self.max_variables],
117 energy: -100.0,
118 frequency: 10,
119 }])
120 }
121
122 fn to_sample_result(
124 &self,
125 solution: &DASolution,
126 var_map: &HashMap<String, usize>,
127 ) -> SampleResult {
128 let mut assignments = HashMap::new();
129
130 for (var_name, &index) in var_map {
131 if index < solution.configuration.len() {
132 assignments.insert(var_name.clone(), solution.configuration[index] == 1);
133 }
134 }
135
136 SampleResult {
137 assignments,
138 energy: solution.energy,
139 occurrences: solution.frequency as usize,
140 }
141 }
142}
143
144#[derive(Debug, Clone)]
146struct DASolution {
147 configuration: Vec<u8>,
149 energy: f64,
151 frequency: u32,
153}
154
155impl Sampler for FujitsuDigitalAnnealerSampler {
156 fn run_qubo(
157 &self,
158 model: &(Array2<f64>, HashMap<String, usize>),
159 shots: usize,
160 ) -> SamplerResult<Vec<SampleResult>> {
161 let (qubo, var_map) = model;
162
163 if qubo.shape()[0] > self.max_variables {
165 return Err(SamplerError::InvalidModel(format!(
166 "Problem size {} exceeds Digital Annealer limit of {}",
167 qubo.shape()[0],
168 self.max_variables
169 )));
170 }
171
172 let job_id = self.submit_problem(qubo)?;
174
175 let timeout = Duration::from_millis(self.config.annealing_time as u64 + 5000);
177 let da_solutions = self.get_results(&job_id, timeout)?;
178
179 let mut results: Vec<SampleResult> = da_solutions
181 .iter()
182 .map(|sol| self.to_sample_result(sol, var_map))
183 .collect();
184
185 results.sort_by(|a, b| {
187 a.energy
188 .partial_cmp(&b.energy)
189 .unwrap_or(std::cmp::Ordering::Equal)
190 });
191
192 results.truncate(shots);
194
195 Ok(results)
196 }
197
198 fn run_hobo(
199 &self,
200 _hobo: &(scirs2_core::ndarray::ArrayD<f64>, HashMap<String, usize>),
201 _shots: usize,
202 ) -> SamplerResult<Vec<SampleResult>> {
203 Err(SamplerError::NotImplemented(
204 "HOBO not supported by Fujitsu hardware".to_string(),
205 ))
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_fujitsu_config() {
215 let mut config = FujitsuConfig::default();
216 assert_eq!(config.annealing_time, 1000);
217 assert_eq!(config.num_replicas, 16);
218 }
219
220 #[test]
221 fn test_connectivity_types() {
222 let sampler = FujitsuDigitalAnnealerSampler::new(FujitsuConfig::default())
223 .with_connectivity(ConnectivityType::KingsGraph);
224
225 match sampler.connectivity {
226 ConnectivityType::KingsGraph => (),
227 _ => panic!("Wrong connectivity type"),
228 }
229 }
230}