pub struct Program {
pub name: Option<String>,
pub spins: usize,
pub bias: Vec<(usize, f64)>,
pub factors: Vec<Factor>,
pub colors: Vec<Vec<usize>>,
pub encodings: Vec<EncodedVar>,
pub schedule: Schedule,
pub observe: Vec<String>,
pub target: Option<String>,
pub price: Option<String>,
}Expand description
A complete program.
Fields§
§name: Option<String>§spins: usize§bias: Vec<(usize, f64)>§factors: Vec<Factor>§colors: Vec<Vec<usize>>§encodings: Vec<EncodedVar>§schedule: Schedule§observe: Vec<String>§target: Option<String>§price: Option<String>Implementations§
Source§impl Program
impl Program
Sourcepub fn from_graph(g: &Graph, schedule: &Schedule) -> Program
pub fn from_graph(g: &Graph, schedule: &Schedule) -> Program
Build a program from a graph and a schedule.
Sourcepub fn to_graph(&self) -> Result<Graph, FtpError>
pub fn to_graph(&self) -> Result<Graph, FtpError>
Rebuild a graph from this program. Factors of arity above two are refused here rather than silently dropped; lowering them to pairwise is a separate pass with its own ancillas.
Examples found in repository?
examples/hubo_vs_reduction.rs (line 139)
109fn main() {
110 let cases: [(usize, usize, usize); 4] = [(24, 3, 32), (32, 3, 48), (24, 4, 24), (40, 3, 60)];
111 let budgets: [usize; 6] = [1, 4, 16, 64, 256, 1024];
112
113 println!("hubo native vs Rosenberg reduction, on the same terms");
114 println!(
115 "mean best energy of the ORIGINAL model over {SEEDS} seeds; lower is better.\n\
116 The native arm runs once, at 1x. Every reduced column is a MULTIPLE of that same budget.\n"
117 );
118
119 print!(
120 "{:>4} {:>2} {:>4} {:>6} {:>4} {:>7} {:>8} ",
121 "n", "k", "trm", "spins", "anc", "pen/w", "native"
122 );
123 for b in budgets {
124 print!("{:>9}", format!("red {b}x"));
125 }
126 println!(" broken");
127
128 for (n, k, t) in cases {
129 let mut native = 0.0f64;
130 let mut reduced = [0.0f64; 6];
131 let mut broken = 0usize;
132 let (mut ancillas, mut rspins, mut penalty) = (0usize, 0usize, 0.0f64);
133
134 for seed in 0..SEEDS {
135 let terms = instance(n, k, t, seed);
136 let h = hubo_of(&terms, n);
137 let prog = Program::from_ftp(&ftp_of(&terms, n)).expect("a well-formed program");
138 let red = reduce::to_pairwise(&prog).expect("a reducible program");
139 let g = red.program.to_graph().expect("a pairwise graph");
140 ancillas = red.ancillas;
141 rspins = red.program.spins;
142 penalty = red.penalty;
143
144 let p = hubo::Params {
145 beta_min: 0.05,
146 beta_max: 8.0,
147 stages: STAGES,
148 sweeps_per_stage: SWEEPS,
149 };
150 native += hubo::anneal(&h, &p, seed).energy;
151
152 let ladder = geometric_ladder(REDUCED_BETA_MIN, 8.0, STAGES);
153 for (i, mult) in budgets.iter().enumerate() {
154 let sched: Vec<(f64, usize)> =
155 ladder.iter().map(|&b| (b, SWEEPS * mult)).collect();
156 let (state, reduced_e) = tempering::anneal(&g, &sched, seed, None);
157 let original_e = h.energy(&state[..n]);
158 reduced[i] += original_e;
159 // Comparing the two energies IS the ancilla check, and it needs no knowledge of
160 // which spins are ancillas or of how they were defined.
161 if ((reduced_e + red.offset) - original_e).abs() > 1e-6 {
162 broken += 1;
163 }
164 }
165 }
166
167 let m = SEEDS as f64;
168 print!(
169 "{n:>4} {k:>2} {t:>4} {rspins:>6} {ancillas:>4} {:>7.0} {:>8.2} ",
170 penalty,
171 native / m
172 );
173 for r in reduced {
174 print!("{:>9.2}", r / m);
175 }
176 println!(" {:>3}/{}", broken, SEEDS as usize * budgets.len());
177 }
178
179 println!(
180 "\n'anc' is the ancillas the reduction added and 'spins' the graph it had to search: each \
181 one is a variable\nthe answer depends on and the question never mentioned. The native path \
182 adds none.\n\n\
183 'pen/w' is the penalty the reduction chose, against term weights of 1. That ratio is the \
184 mechanism: any\nsingle flip that would move the search must first pay it, so the landscape \
185 is rigid and a single-flip\nsampler cannot traverse it. 'broken' counts runs whose ancillas \
186 did not hold, and it stays at zero --\nwhich is the confirmation, not a null result: the \
187 reduced arm is stuck inside the feasible region\nrather than wandering out of it.\n\n\
188 The budget columns are the finding. If the reduced arm caught up at 64x or 256x, the cost \
189 of quadratising\nwould be compute, and compute is buyable."
190 );
191}Sourcepub fn to_ftp(&self) -> String
pub fn to_ftp(&self) -> String
Serialise. The output re-parses to an equal program and re-writes byte-identically.
Sourcepub fn from_ftp(text: &str) -> Result<Program, FtpError>
pub fn from_ftp(text: &str) -> Result<Program, FtpError>
Parse. Errors carry the line number, because a format nobody can debug is a format nobody adopts.
Examples found in repository?
examples/hubo_vs_reduction.rs (line 137)
109fn main() {
110 let cases: [(usize, usize, usize); 4] = [(24, 3, 32), (32, 3, 48), (24, 4, 24), (40, 3, 60)];
111 let budgets: [usize; 6] = [1, 4, 16, 64, 256, 1024];
112
113 println!("hubo native vs Rosenberg reduction, on the same terms");
114 println!(
115 "mean best energy of the ORIGINAL model over {SEEDS} seeds; lower is better.\n\
116 The native arm runs once, at 1x. Every reduced column is a MULTIPLE of that same budget.\n"
117 );
118
119 print!(
120 "{:>4} {:>2} {:>4} {:>6} {:>4} {:>7} {:>8} ",
121 "n", "k", "trm", "spins", "anc", "pen/w", "native"
122 );
123 for b in budgets {
124 print!("{:>9}", format!("red {b}x"));
125 }
126 println!(" broken");
127
128 for (n, k, t) in cases {
129 let mut native = 0.0f64;
130 let mut reduced = [0.0f64; 6];
131 let mut broken = 0usize;
132 let (mut ancillas, mut rspins, mut penalty) = (0usize, 0usize, 0.0f64);
133
134 for seed in 0..SEEDS {
135 let terms = instance(n, k, t, seed);
136 let h = hubo_of(&terms, n);
137 let prog = Program::from_ftp(&ftp_of(&terms, n)).expect("a well-formed program");
138 let red = reduce::to_pairwise(&prog).expect("a reducible program");
139 let g = red.program.to_graph().expect("a pairwise graph");
140 ancillas = red.ancillas;
141 rspins = red.program.spins;
142 penalty = red.penalty;
143
144 let p = hubo::Params {
145 beta_min: 0.05,
146 beta_max: 8.0,
147 stages: STAGES,
148 sweeps_per_stage: SWEEPS,
149 };
150 native += hubo::anneal(&h, &p, seed).energy;
151
152 let ladder = geometric_ladder(REDUCED_BETA_MIN, 8.0, STAGES);
153 for (i, mult) in budgets.iter().enumerate() {
154 let sched: Vec<(f64, usize)> =
155 ladder.iter().map(|&b| (b, SWEEPS * mult)).collect();
156 let (state, reduced_e) = tempering::anneal(&g, &sched, seed, None);
157 let original_e = h.energy(&state[..n]);
158 reduced[i] += original_e;
159 // Comparing the two energies IS the ancilla check, and it needs no knowledge of
160 // which spins are ancillas or of how they were defined.
161 if ((reduced_e + red.offset) - original_e).abs() > 1e-6 {
162 broken += 1;
163 }
164 }
165 }
166
167 let m = SEEDS as f64;
168 print!(
169 "{n:>4} {k:>2} {t:>4} {rspins:>6} {ancillas:>4} {:>7.0} {:>8.2} ",
170 penalty,
171 native / m
172 );
173 for r in reduced {
174 print!("{:>9.2}", r / m);
175 }
176 println!(" {:>3}/{}", broken, SEEDS as usize * budgets.len());
177 }
178
179 println!(
180 "\n'anc' is the ancillas the reduction added and 'spins' the graph it had to search: each \
181 one is a variable\nthe answer depends on and the question never mentioned. The native path \
182 adds none.\n\n\
183 'pen/w' is the penalty the reduction chose, against term weights of 1. That ratio is the \
184 mechanism: any\nsingle flip that would move the search must first pay it, so the landscape \
185 is rigid and a single-flip\nsampler cannot traverse it. 'broken' counts runs whose ancillas \
186 did not hold, and it stays at zero --\nwhich is the confirmation, not a null result: the \
187 reduced arm is stuck inside the feasible region\nrather than wandering out of it.\n\n\
188 The budget columns are the finding. If the reduced arm caught up at 64x or 256x, the cost \
189 of quadratising\nwould be compute, and compute is buyable."
190 );
191}Trait Implementations§
impl StructuralPartialEq for Program
Auto Trait Implementations§
impl Freeze for Program
impl RefUnwindSafe for Program
impl Send for Program
impl Sync for Program
impl Unpin for Program
impl UnsafeUnpin for Program
impl UnwindSafe for Program
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more