//! A contraction's cost with and without sweep seeds: the trees that absorb a //! circuit's tensors qubit by qubit or time by time ([`sweep_path`]), beside the //! hyper-optimiser's own. //! //! ```text //! cargo run --release --example tn_sweep --features quantum_qasm,quantum_tn -- CIRCUIT.qasm [TRIALS] [RESTARTS] //! ``` //! //! Prints, for one amplitude of a seeded random output: each sweep's cost as //! given, the search's best without seeds, and with them. The costs are log10 //! of complex multiply-adds and log2 of the largest intermediate. use std::time::Instant; use wai_quantum::quantum_tn::{Network, PathOptions, find_path_restarts, find_path_restarts_seeded, path_cost, sweep_orders, sweep_path, tensor_places}; fn main() { let args: Vec = std::env::args().collect(); let src = std::fs::read_to_string(&args[1]).expect("the circuit reads"); let trials: usize = args.get(2).map_or(64, |s| s.parse().unwrap()); let restarts: usize = args.get(3).map_or(1, |s| s.parse().unwrap()); let p = wai_quantum::qasm::parse(&src).expect("the program parses"); let n = p.n_qubits; let mut s = 0x9e37_79b9_7f4a_7c15u64; let bits: Vec = (0..n) .map(|_| { s = s.wrapping_add(0x9e37_79b9_7f4a_7c15); let mut z = s; z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); ((z ^ (z >> 31)) & 1) as u8 }) .collect(); let (mut net, place) = Network::amplitude_split_placed(n, &p.matrices(), &bits, &[]).expect("the network builds"); net.reduce(); let shape = net.shape(); println!("{n} qubits, {} gates, {} tensors after reduction", p.ops.len(), shape.len()); let sweeps: Vec<_> = sweep_orders(&tensor_places(&net, &place)).iter().map(|o| sweep_path(o)).collect(); for (name, path) in ["qubit by qubit", "time by time"].iter().zip(&sweeps) { let c = path_cost(&shape, &net.dims, &net.open, path); println!(" sweep {name:<15} log10 flops {:>7.3} log2 largest {:>5.1}", c.log10_flops(), c.log2_size()); } let opts = PathOptions { trials, ..PathOptions::default() }; for (name, seeds) in [("search", &[][..]), ("search + sweeps", &sweeps[..])] { let t = Instant::now(); let plan = if seeds.is_empty() { find_path_restarts(&shape, &net.dims, &net.open, &opts, restarts) } else { find_path_restarts_seeded(&shape, &net.dims, &net.open, &opts, restarts, seeds) }; println!(" {name:<21} log10 flops {:>7.3} log2 largest {:>5.1} in {:.1?}", plan.total_flops().log10(), plan.per_slice.log2_size(), t.elapsed()); } }