problemreductions/rules/
spinglass_maxcut.rs1use crate::models::graph::MaxCut;
7use crate::models::graph::SpinGlass;
8use crate::reduction;
9use crate::rules::traits::{ReduceTo, ReductionResult};
10use crate::topology::{Graph, SimpleGraph};
11use crate::types::WeightElement;
12use num_traits::Zero;
13
14#[derive(Debug, Clone)]
16pub struct ReductionMaxCutToSG<W> {
17 target: SpinGlass<SimpleGraph, W>,
18}
19
20impl<W> ReductionResult for ReductionMaxCutToSG<W>
21where
22 W: WeightElement
23 + crate::variant::VariantParam
24 + PartialOrd
25 + num_traits::Num
26 + num_traits::Zero
27 + num_traits::Bounded
28 + std::ops::AddAssign
29 + std::ops::Mul<Output = W>
30 + From<i32>,
31{
32 type Source = MaxCut<SimpleGraph, W>;
33 type Target = SpinGlass<SimpleGraph, W>;
34
35 fn target_problem(&self) -> &Self::Target {
36 &self.target
37 }
38
39 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
40 target_solution.to_vec()
41 }
42}
43
44#[reduction(
45 overhead = {
46 num_spins = "num_vertices",
47 num_interactions = "num_edges",
48 }
49)]
50impl ReduceTo<SpinGlass<SimpleGraph, i32>> for MaxCut<SimpleGraph, i32> {
51 type Result = ReductionMaxCutToSG<i32>;
52
53 fn reduce_to(&self) -> Self::Result {
54 let n = self.graph().num_vertices();
55 let edges_with_weights = self.edges();
56
57 let interactions: Vec<((usize, usize), i32)> = edges_with_weights
75 .into_iter()
76 .map(|(u, v, w)| ((u, v), w))
77 .collect();
78
79 let onsite = vec![0i32; n];
81
82 let target = SpinGlass::<SimpleGraph, i32>::new(n, interactions, onsite);
83
84 ReductionMaxCutToSG { target }
85 }
86}
87
88#[derive(Debug, Clone)]
90pub struct ReductionSGToMaxCut<W> {
91 target: MaxCut<SimpleGraph, W>,
92 ancilla: Option<usize>,
94}
95
96impl<W> ReductionResult for ReductionSGToMaxCut<W>
97where
98 W: WeightElement
99 + crate::variant::VariantParam
100 + PartialOrd
101 + num_traits::Num
102 + num_traits::Zero
103 + num_traits::Bounded
104 + std::ops::AddAssign
105 + std::ops::Mul<Output = W>
106 + From<i32>,
107{
108 type Source = SpinGlass<SimpleGraph, W>;
109 type Target = MaxCut<SimpleGraph, W>;
110
111 fn target_problem(&self) -> &Self::Target {
112 &self.target
113 }
114
115 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
116 match self.ancilla {
117 None => target_solution.to_vec(),
118 Some(anc) => {
119 let mut sol = target_solution.to_vec();
121 if sol[anc] == 1 {
122 for x in sol.iter_mut() {
123 *x = 1 - *x;
124 }
125 }
126 sol.remove(anc);
127 sol
128 }
129 }
130 }
131}
132
133#[reduction(
134 overhead = {
135 num_vertices = "num_spins",
136 num_edges = "num_interactions",
137 }
138)]
139impl ReduceTo<MaxCut<SimpleGraph, i32>> for SpinGlass<SimpleGraph, i32> {
140 type Result = ReductionSGToMaxCut<i32>;
141
142 fn reduce_to(&self) -> Self::Result {
143 let n = self.num_spins();
144 let interactions = self.interactions();
145 let fields = self.fields();
146
147 let need_ancilla = fields.iter().any(|h| !h.is_zero());
149 let total_vertices = if need_ancilla { n + 1 } else { n };
150 let ancilla_idx = if need_ancilla { Some(n) } else { None };
151
152 let mut edges = Vec::new();
153 let mut weights = Vec::new();
154
155 for ((i, j), w) in interactions {
157 edges.push((i, j));
158 weights.push(w);
159 }
160
161 if need_ancilla {
165 for (i, h) in fields.iter().enumerate() {
166 if !h.is_zero() {
167 edges.push((i, n));
168 weights.push(*h);
169 }
170 }
171 }
172
173 let target = MaxCut::new(SimpleGraph::new(total_vertices, edges), weights);
174
175 ReductionSGToMaxCut {
176 target,
177 ancilla: ancilla_idx,
178 }
179 }
180}
181
182#[cfg(test)]
183#[path = "../unit_tests/rules/spinglass_maxcut.rs"]
184mod tests;