pub struct Hitachi {
pub last_energies: Vec<f64>,
pub last_execution_ns: u64,
/* private fields */
}Expand description
The Hitachi annealer as a backend.
§Nothing here contacts anyone until you set it up
Constructing a Hitachi, describing its fabric, laying a program out on the
grid and embedding one all run entirely locally. The single network call in this crate lives in
Device::run, and reaching it takes a token you supplied, a program you laid out, and a call
you made. There is no ambient default: Hitachi::from_env returns Err when ACW_TOKEN is
unset rather than falling back to anything, and the crate reads no other environment variable,
no config file and no credential store.
Fields§
§last_energies: Vec<f64>Last raw energies returned, in the machine’s own sign convention.
last_execution_ns: u64Nanoseconds the machine reported for the last run.
Implementations§
Source§impl Hitachi
impl Hitachi
Sourcepub fn new(token: impl Into<String>, machine: Machine) -> Hitachi
pub fn new(token: impl Into<String>, machine: Machine) -> Hitachi
token comes from Annealing Cloud Web. Read it from the environment; do not commit it.
Sourcepub fn from_env(machine: Machine) -> Result<Hitachi, String>
pub fn from_env(machine: Machine) -> Result<Hitachi, String>
From ACW_TOKEN in the environment.
Examples found in repository?
9fn main() {
10 let mut d = match Hitachi::from_env(Machine::Asic) {
11 Ok(d) => d,
12 Err(e) => { eprintln!("{e}"); return; }
13 };
14 let f = d.fabric();
15 println!("fabric {} | {:?} | {} sites | degree {} | coupling {:?}",
16 f.name, f.topology, f.max_spins.unwrap(), f.max_degree.unwrap(), f.coupling_precision);
17
18 // A 4x4 antiferromagnetic block, laid out row-major so every coupling is King-adjacent.
19 let side = Machine::Asic.side();
20 let mut src = format!("ftp 1\nname acw-4x4-antiferro\nspins {}\n", 3 * side + 4);
21 let mut edges = 0;
22 for y in 0..4usize {
23 for x in 0..4usize {
24 let i = y * side + x;
25 if x + 1 < 4 { src.push_str(&format!("factor -1 {i} {}\n", i + 1)); edges += 1; }
26 if y + 1 < 4 { src.push_str(&format!("factor -1 {i} {}\n", i + side)); edges += 1; }
27 }
28 }
29 let p = Program::from_ftp(&src).expect("program");
30 println!("program {} spins declared, {edges} couplings, digest {:016x}", p.spins, p.digest());
31
32 let bad = d.program(&p);
33 if !bad.is_empty() {
34 for u in &bad { println!("REFUSED: {u}"); }
35 return;
36 }
37
38 match d.run(&Schedule::geometric(0.1, 10.0, 20, 50), 1) {
39 Err(e) => println!("run failed: {e}"),
40 Ok(state) => {
41 let g = p.to_graph().unwrap();
42 println!("machine energy (their sign) {:?}", d.last_energies);
43 println!("execution {:.3} ms on the ASIC", d.last_execution_ns as f64 / 1e6);
44 println!("our energy {}", g.energy(&state));
45 let ok = (0..4).all(|y| (0..4).all(|x| {
46 let i = y * side + x;
47 state[i] == if (x + y) % 2 == 0 { state[0] } else { -state[0] }
48 }));
49 println!("checkerboard {}", if ok { "yes - every bond satisfied" } else { "no" });
50 println!("ledger {} node updates", d.ledger().samples);
51 }
52 }
53}Sourcepub fn with_endpoint(self, url: impl Into<String>) -> Hitachi
pub fn with_endpoint(self, url: impl Into<String>) -> Hitachi
Send somewhere other than ACW_ENDPOINT — a mock, a proxy, or a self-hosted instance.
The address a driver posts to is the caller’s decision, not the driver’s. Without this the
only way to exercise Device::run at all was to send a real job to a third party, which
is why nothing in this crate’s tests has ever covered it.
Sourcepub fn endpoint(&self) -> &str
pub fn endpoint(&self) -> &str
Where this instance will post. See Hitachi::with_endpoint.
Sourcepub fn place(&mut self, p: &Program) -> Result<Embedding, String>
pub fn place(&mut self, p: &Program) -> Result<Embedding, String>
Place a program on the grid, embedding it if it does not already fit.
Hitachi::layout requires a program whose couplings are already King-adjacent under the
row-major layout — which is a real constraint on the caller and, until ferrotherm::embed
existed, one this driver could only refuse. This tries that first, and when it fails uses
minor embedding to find a placement.
Returns the embedding, which is needed to read the answer back: a variable may now occupy
several sites, and ferrotherm::embed::unembed turns those back into one value and says
which chains broke.
The embedded model is not the model that was written. Chains add couplings at
chain_strength, and a program that fitted the grid already is placed unchanged, so the
returned embedding is the identity and the distinction costs nothing.
Sourcepub fn layout(&mut self, p: &Program) -> Result<(), LayoutError>
pub fn layout(&mut self, p: &Program) -> Result<(), LayoutError>
Lay a program out on the grid, negating every weight for their sign convention.
Requires every coupling to be King-adjacent already. Hitachi::place embeds when it is
not, and is what a caller who has not laid their model out by hand wants.