Function gen

Source
pub fn gen<T, U, F, G, H, E>(
    (nodes, edges): Graph<T, U>,
    n: usize,
    f: F,
    g: G,
    h: H,
    settings: &GenerateSettings,
) -> Result<Graph<T, U>, (Graph<T, U>, E)>
where T: Eq + Hash + Clone, F: Fn(&T, usize) -> Result<(T, U), E>, G: Fn(&T) -> bool, H: Fn(&U, &U) -> Result<U, Option<E>>, E: From<GenerateError>,
Expand description

Generates a graph from:

  • an initial seed state a
  • maximum n edges
  • a function f to generate a new node with edge
  • a filter g to post-process nodes
  • a composer h to use for transforming edges when nodes are filtered
  • settings to control usage of memory

Returns a list of nodes and a list of edges.

  • Ok if generation was successful without hitting memory limits
  • Err if generation hit memory limits

Waiting with filtering until post-processing makes it possible to create an edge between nodes that require multiple steps.

The maximum number of edges is usually determined from the length of a list of valid operations.

§Error handling

The algorithm continues to post-processing when hitting memory limits. It is assumed that one wants to make use of the data generated, where memory limits are met often due to combinatorial explosions.

The algorithm assumes that there are other limits besides those in GenerateSettings. To handle errors, one adds a type that implements From<GenerateError>. The unit type () can be used when error handling is not needed.

Tip: Since this function requires 6 generic type arguments, it is easier to set the error type on the output type and let Rust infer the rest.

For example:

let (nodes, edges) = match gen(start, n, f, g, h, &settings) {
    Ok(x) => x,
    Err((x, ())) => x,
};

When an error happens during composing edges, one can choose whether to report the error with Err(Some(err)), or ignore it with Err(None). This is useful because sometimes you want to filter edges without reporting errors. The algorithm assumes that one wishes to continue generating the graph when encountering an error. Only the first error will be reported.

Examples found in repository?
examples/eq.rs (line 92)
39fn main() {
40    // Change this to control the number of terms in the equation.
41    let n: usize = if let Some(x) = std::env::args_os().skip(1).take(1).next() {
42        usize::from_str(&x.into_string().expect("number")).unwrap()
43    } else {
44        3
45    };
46    // Change this to control how many
47    let solution_terms: usize = if let Some(x) = std::env::args_os().skip(2).take(1).next() {
48        usize::from_str(&x.into_string().expect("number")).unwrap()
49    } else {
50        1
51    };
52
53    // Putting all terms except the last one
54    let start = Eq {
55        side: {
56            if solution_terms == 1 && n > 0 {
57                let mut res = vec![true; n-1];
58                res.push(false);
59                res
60            } else {
61                vec![true; n]
62            }
63        },
64        positive: vec![true; n],
65    };
66
67    // Swap side and sign on the chosen term.
68    let f = |eq: &Eq, ind: usize| {
69        let mut eq = eq.clone();
70        eq.side[ind] = !eq.side[ind];
71        eq.positive[ind] = !eq.positive[ind];
72        Ok((eq, Swap(vec![ind])))
73    };
74    // Filter nodes to those with the specified number of solutions.
75    let g = |eq: &Eq| eq.len_right() == solution_terms;
76    // Join operations.
77    // Since these swap operations are commutative, require order.
78    let h = |a: &Swap, b: &Swap| if a.0 >= b.0 {Err(None)} else {Ok(Swap({
79        let mut a = a.0.clone();
80        a.extend_from_slice(&b.0);
81        a.sort();
82        a
83    }))};
84
85    let settings = GenerateSettings {
86        max_nodes: 1000,
87        max_edges: 1000,
88    };
89
90    let seed = (vec![start], vec![]);
91    // Generate graph.
92    let (eqs, mut edges) = match gen(seed, n, f, g, h, &settings) {
93        Ok(x) => x,
94        Err((x, ())) => x,
95    };
96
97    // Remove all edges that are not bidirectional.
98    bidir(&mut edges);
99    edges.sort();
100    for i in 0..eqs.len() {
101        println!("{}: {}", i, eqs[i]);
102    }
103    for i in 0..edges.len() {
104        println!("{:?}", edges[i]);
105    }
106
107    println!("(nodes, edges): ({}, {})", eqs.len(), edges.len());
108}