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
//! 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, which means it does not use memory
//! in the compiled program. The phantom variable 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 a generic program, the algorithms to examine the structure
//! follows from the construction of the space.
//!
//! This makes it possible to solve tasks such as:
//!
//! - Compute upper bounds for many problems
//! - Store data with a non-trivial structure
//! - Convert from and to natural numbers
//! - Iterate through all elements of a space
//! - Pick a random object of the space
//!
//! Iterating through all elements of a 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.
//!
//! Picking 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 represent 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.
extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;
use PhantomData;
pub use Construct;
pub use Count;
pub use Zero;
pub use ToIndex;
pub use ToPos;
pub use PowerSet;
pub use DimensionN;
pub use Dimension;
pub use Pair;
pub use EqPair;
pub use NeqPair;
pub use SqPair;
pub use Permutation;
pub use Context;
pub use DirectedContext;
pub use ;
pub use ;
pub use BigUint;
/// Used by the final subspace.
;
/// Used to combine the dimensional and position types.
;
/// N - numeric type
/// T - discrete space