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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
#![deny(missing_docs)] //! Combinatorial phantom types for discrete mathematics. //! //! All discrete spaces have the following functions: //! //! ~~~ignore //! fn count(dim) -> usize; //! fn to_index(dim, pos) -> usize; //! fn to_pos(dim, index, &mut pos); //! ~~~ //! //! A discrete space is countable and has a one-to-one map //! with the natural numbers. //! //! For example, a pair of natural numbers is a discrete space. //! There exists an algorithm that converts each pair of numbers //! into a number. Likewise there exists an algorithm that //! takes a number and converts it into a pair. //! //! To construct a pair, you write: //! //! ~~~ignore //! let x: Pair<Data> = Construct::new(); //! ~~~ //! //! The `x` above is a phantom variable, it does not use memory //! in the compiled program. It represents the discrete space //! that we have constructed. Now we can call methods on the space //! to examine its discrete structure. //! //! A pair can be visualized as edges between points. //! If we have 4 points then we can create 6 edges: //! //! ```text //! o---o //! |\ /| //! | X | //! |/ \| //! o---o //! ``` //! //! To check this we can write: //! //! ~~~ignore //! let dim = 4; // number of points //! assert_eq!(x.count(dim), 6); // count edges //! ~~~ //! //! Phantom types makes it possible to construct advanced discrete spaces. //! By using generic program, the algorithms to examine the structure //! follows from the construction of the space. //! //! This makes it possible to solve tasks as: //! //! - Compute upper bounds for certain problems //! - Store data with a non-trivial structure //! - Convert from and to natural numbers //! - Iterate through the space //! - Pick a random object of the space //! //! Iterating through the space can be done simply //! by counting from zero up to the size of the space. //! For each number, we convert to a position within the space. //! //! Pick a random object of the space can be done by generating //! a random number between 0 and the size of the space. //! //! ### Advanced spaces //! //! Phantom types are used because they represents the general spaces. //! For example, we can represent a general two-dimensional space, //! instead of binding the type to the size. //! //! For any constructed space, there is a dimension and position type. //! The dimension and position types are compositions, //! given by the type of the constructed space. use std::marker::PhantomData; pub use construct::Construct; pub use count::Count; pub use to_index::ToIndex; pub use to_pos::ToPos; pub use zero::Zero; pub use power_set::PowerSet; pub use dimension_n::DimensionN; pub use dimension::Dimension; pub use pair::Pair; pub use eq_pair::EqPair; pub use neq_pair::NeqPair; pub use permutation::Permutation; pub use context::Context; pub use directed_context::DirectedContext; pub use either::{Either, Select}; mod construct; mod count; mod to_index; mod to_pos; mod zero; mod power_set; mod dimension_n; mod dimension; mod pair; mod eq_pair; mod neq_pair; mod permutation; mod context; mod directed_context; mod subspace; mod either; /// Used by the final subspace. #[derive(Copy, Clone)] pub struct Data; /// Used to combine the dimensional and position types. pub struct Of<T>(PhantomData<T>); #[cfg(test)] pub fn does_count<T, U>() where T: Count<U> {} #[cfg(test)] pub fn does_zero<T, U, V>() where T: Zero<U, V> {} #[cfg(test)] pub fn does_to_index<T, U, V>() where T: ToIndex<U, V> {} #[cfg(test)] pub fn does_to_pos<T, U, V>() where T: ToPos<U, V> {} // T - discrete space // U - dimension // V - Position #[cfg(test)] pub fn is_complete<T, U, V>() where T: Count<U> + Zero<U, V> + ToIndex<U, V> + ToPos<U, V> { does_count::<T, U>(); does_zero::<T, U, V>(); does_to_index::<T, U, V>(); does_to_pos::<T, U, V>(); }