chrono_probe/
lib.rs

1//! # Chrono-probe
2//!
3//! **Chrono-probe** is a library for measuring the time complexity of algorithms.
4//!
5//! In order to measure the time complexity of an algorithm, you need to provide an algorithm (or
6//! more) and a way to generate inputs for the algorithm. The library will then measure the time
7//! it takes for the algorithm to run on the generated inputs of various lengths. In this way, it
8//! is possible to obtain a plot of the time taken by the algorithm as a function of the input size.
9//!
10//! The library is designed to be as flexible as possible. It is possible to use the library to
11//! measure the time complexity of any algorithm, as long as the algorithm can be expressed as a
12//! function that takes an input and returns an output.
13//!
14//! ## How to use chrono-probe
15//!
16//! In this section, we will show how to use **chrono-probe** to measure the time complexity
17//! of a sorting algorithm. We will use the `quicksort` algorithm as an example. This example and
18//! more can be found in the [examples](https://github.com/ADS-laboratory/chrono-probe/tree/lib/examples) folder.
19//!
20//! The implementation of the quicksort algorithm is not important for this example, the definition
21//! would look something like this:
22//! ```ignore
23//! fn quick_sort<T: Ord + Clone>(v: &mut [T]) {
24//!    // ...
25//! }
26//! ```
27//!
28//! The first step is to define a type that represents the input to the algorithm. In this case we
29//! want to measure the time complexity of sorting vectors of u32, so we define a new type that is
30//! a vector of u32. This is done because rust does not allow us to implement traits for types
31//! defined in other crates and we need to implement the [Input]() trait for our type.
32//!
33//! ```ignore
34//! #[derive(Clone)]
35//! pub struct InputVec(Vec<u32>);
36//! ```
37//!
38//! We can also implement `Deref` and `DerefMut` for InputVec, so that we can use it as a `Vec<u32>`.
39//! This is not necessary, but it makes it easier to use.
40//!
41//! ```ignore
42//! impl Deref for InputVec {
43//!     type Target = Vec<u32>;
44//!
45//!     fn deref(&self) -> &Self::Target {
46//!         &self.0
47//!     }
48//! }
49//!
50//! impl DerefMut for InputVec {
51//!     fn deref_mut(&mut self) -> &mut Self::Target {
52//!         &mut self.0
53//!     }
54//! }
55//! ```
56//!
57//! Now we can define the quicksort algorithm as a function that takes an InputVec.
58//! ```ignore
59//! fn quick_sort_measure(v: &mut InputVec) {
60//!    quick_sort(v);
61//! }
62//! ```
63//!
64//! The next step is to implement the [input::Input] trait for `InputVec`. This trait defines how to generate
65//! inputs for the algorithm and what the size of the input is. In this case we don't need to choose
66//! between different input generators, so we don't need a Builder, for more information on how to
67//! use Builders see the documentation for the [input::Input] trait.
68//!
69//! ```ignore
70//! impl Input for InputVec {
71//!    // We don't need a Builder.
72//!     type Builder = ();
73//!
74//!     // Return the size of the input, in this case the size is the length of the vector.
75//!     fn get_size(&self) -> usize {
76//!         self.len()
77//!     }
78//!
79//!     // Generate a vector of the given size and fill it with random numbers.
80//!     fn generate_input(size: usize, _builder: &Self::Builder) -> Self {
81//!         let mut rng = thread_rng();
82//!         let mut v = Vec::with_capacity(size);
83//!         for _ in 0..size {
84//!             let rand: u32 = rng.gen();
85//!             v.push(rand);
86//!         }
87//!         InputVec(v)
88//!     }
89//! }
90//! ```
91//!
92//! Now we implemented all the necessary traits and we can use the library to measure the algorithm.
93//!
94//!
95//! In the main function we create a distribution for the length of the vectors. Here we use a linear
96//! distribution with a minimum of 1000 and a maximum of 500_000. So all the vectors will have a
97//! length between 1000 and 500_000 and the length will be chosen uniformly at random.
98//!
99//! ```ignore
100//! let length_distribution = Linear::new(1000..=500_000);
101//! ```
102//!
103//! The next step is to create a builder for the vectors. The builder is used to generate the
104//! vectors, we only need to specify the distribution for the length of the vectors and because
105//! we don't need a Builder for the InputVec, we can use `()` as the Builder.
106//!
107//! ```ignore
108//! let vector_builder = InputBuilder::new(length_distribution, ());
109//! ```
110//!
111//! Now we can build the vectors. Here we build 200 vectors, 10 of each length.
112//!
113//! ```ignore
114//! let mut vectors = vector_builder.build_with_repetitions(200, 10);
115//! ```
116//!
117//! Finally we can measure the algorithm. We need to specify the algorithm, the input and the
118//! relative error. The relative error is used to determine how many times the algorithm should be
119//! run for each input size. The algorithm will be run until the relative error is less than the
120//! given relative error. We use the [`measurements::measure_mut`] function because the algorithm takes a mutable
121//! reference to the input.
122//!
123//! ```ignore
124//! // Create a slice of the algorithms we want to measure
125//! let algorithms: &[(fn(&mut input::InputVec), &str); 1] = &[
126//!  (quick_sort_input, "Quick sort"),
127//! ];
128//!
129//! // Measure the algorithms on the vectors, given a relative error of 0.001
130//! let results = measure_mut(&mut vectors, algorithms, 0.001);
131//! ```
132//!
133//! The results are returned as a vector of [`measurements::Measurement`]s. Each measurement contains the size of
134//! the input, the time it took for the algorithm to run and the relative error of the measurement.
135//!
136//!
137//! Results can be plotted using the [`plot::time_plot`] function.
138//!
139//! ```ignore
140//! // Plot the results
141//! let config = PlotConfig::default()
142//!     .with_title("Sorting algorithms")
143//!     .with_caption("The time plot of sorting algorithms");
144//!
145//! time_plot(file_name, results, &config);
146//! ```
147//!
148//! The entire code and other examples can be found in the [examples](https://github.com/ADS-laboratory/chrono-probe/tree/lib/examples) folder.
149
150#![warn(clippy::all)]
151#![warn(clippy::cargo)]
152#![warn(missing_docs)]
153
154pub mod input;
155pub mod measurements;
156pub mod plot;