1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! Configuration options for running spinoza
use clap::Parser;

use crate::core::CONFIG;

/// Config for simulations that are run using the CLI
#[derive(Clone, Copy, Debug)]
pub struct Config {
    /// The number of threads to distribute the workload.
    /// `u32` is used to represent number of threads since 4,294,967,295 is a
    /// reasonable upperbound. If you have access to a matrioshka brain, and you
    /// need a larger data type, please reach out.
    pub threads: u32,
    /// Whether or not to print the State represented as a table.
    pub print: bool,
    /// The number of qubits that will make up the State.  State vector size is 2^{n}, where n is
    /// the # of qubits. Assuming single precision complex numbers, the upper bound with u8 is
    /// 2^255 * 64 bit ≈ 4.632 * 10^{65} TB (terabytes). Thus, using u8 suffices.
    pub qubits: u8,
}

impl Config {
    /// Get or init the global Config. The default
    pub fn global() -> &'static Config {
        CONFIG.get_or_init(Config::test)
    }

    /// Convert the provided CLI args and turn it into a Config
    pub const fn from_cli(args: QSArgs) -> Config {
        assert!(args.threads > 0 && args.qubits > 0);
        Config {
            threads: args.threads,
            qubits: args.qubits,
            print: args.print,
        }
    }

    fn test() -> Config {
        Config {
            threads: std::thread::available_parallelism()
                .unwrap()
                .get()
                .try_into()
                .expect("Too much power"),
            // no input for tests, so this quantity should not matter
            qubits: 0,
            print: false,
        }
    }
}

/// Representation of the CLI args
#[derive(Parser)]
#[command(author, version, about)]
pub struct QSArgs {
    /// Number of threads to use
    #[clap(short, long)]
    threads: u32,
    /// Whether or not to print the state in tabular format
    #[clap(short, long)]
    print: bool,
    /// The number of qubits to use in the system
    #[clap(short, long)]
    qubits: u8,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn no_args() {
        let config = Config::global();
        assert_eq!(
            config.threads,
            std::thread::available_parallelism()
                .unwrap()
                .get()
                .try_into()
                .expect("Too much power")
        );
        assert_eq!(config.qubits, 0);
        assert!(!config.print);
    }
}