├── .github └── FUNDING.yml ├── .gitignore ├── CHANGES.md ├── Cargo.toml ├── LICENSE ├── README.md ├── assets └── necklaces.ods ├── examples ├── dag.rs ├── directed_context.rs ├── homotopy.rs ├── necklace.rs ├── pair_of_pairs.rs ├── pair_of_powersets.rs ├── sq_pair.rs ├── test.rs ├── triangle_cycles.rs └── world_agent.rs └── src ├── construct.rs ├── context.rs ├── count.rs ├── dimension.rs ├── dimension_n.rs ├── directed_context.rs ├── either.rs ├── eq_pair.rs ├── homotopy.rs ├── lib.rs ├── neq_pair.rs ├── pair.rs ├── permutation.rs ├── power_set.rs ├── space.rs ├── sq_pair.rs ├── subspace.rs ├── to_index.rs ├── to_pos.rs └── zero.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: bvssvni 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *# 4 | *.o 5 | *.so 6 | *.swp 7 | *.old 8 | *.bak 9 | *.kate-swp 10 | *.dylib 11 | *.dSYM 12 | *.dll 13 | *.rlib 14 | *.dummy 15 | *.exe 16 | *-test 17 | /bin/main 18 | /bin/test-internal 19 | /bin/test-external 20 | /doc/ 21 | /target/ 22 | /build/ 23 | /.rust/ 24 | rusti.sh 25 | watch.sh 26 | /examples/** 27 | !/examples/*.rs 28 | !/examples/assets/ 29 | !/bin/assets/ 30 | 31 | Cargo.lock 32 | 33 | /examples/test.rs 34 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # 0.5 2 | 3 | - Added support for `BigUint` 4 | 5 | # 0.4 6 | 7 | - Added `SqPair` space 8 | 9 | # 0.3 10 | 11 | - Added `Homotopy` space 12 | 13 | # 0.2 14 | 15 | - Added `Either` space 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "discrete" 4 | version = "0.5.0" 5 | authors = ["bvssvni "] 6 | keywords = ["mathematics", "combinatorics", "phantom-types"] 7 | description = "Combinatorial phantom types for discrete mathematics" 8 | license = "MIT" 9 | readme = "README.md" 10 | repository = "https://github.com/advancedresearch/discrete.git" 11 | homepage = "https://github.com/advancedresearch/discrete" 12 | exclude = ["assets/*"] 13 | 14 | [lib] 15 | 16 | name = "discrete" 17 | path = "src/lib.rs" 18 | 19 | [dependencies] 20 | num = "0.4.0" 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sven Nilsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # discrete 2 | Combinatorial phantom types for discrete mathematics 3 | 4 | [Change log](./CHANGES.md) 5 | 6 | This library is for constructing algorithms by composition that maps to and from natural numbers. 7 | 8 | For example, a pair is a tuple `(a, b)` where `b > a`. 9 | It can represent an undirected edge between two nodes in a graph. 10 | 11 | A pair can be mapped to and from a natural number. 12 | This can be used to store and retrieve information associated with the edge. 13 | 14 | In this library, a pair is represented as the type `Pair`. 15 | When you need all pair of pairs, you write `Pair>`. 16 | 17 | ### Why? 18 | 19 | Discrete spaces that maps to and from natural numbers have many nice mathematical properties. 20 | For example, it can enumerate all possible structures by listing the natural numbers up to a limit. 21 | 22 | Two structures are equivalent (isomorphic) if they map to and from natural numbers up to the same "count" (often called the "cardinality" in mathematical literature). 23 | Instead of proving isomorphisms directly between `A` and `B`, it is sufficient to prove `A ~=> nat` and `B ~=> nat`, 24 | then prove that they have the same cardinality. 25 | 26 | In principle you could just use numbers, but it would be very hard to write the correct algorithm. 27 | This library gives you the correct algorithms from the type composition. 28 | 29 | Another application of discrete spaces is to obtain upper bounds on complexity. 30 | By encoding more information about the problem into discrete spaces, 31 | one might get lower upper bounds on complexity, and often at the same time learn some new symmetries. 32 | An efficient encoding of a problem into a discrete space can tell you something about how to solve the problem efficiently. 33 | 34 | Discrete spaces are also easy to compose with each other. 35 | You can create one to see what happens when it is composed with other spaces. 36 | 37 | ### How to use discrete spaces in problem solving 38 | 39 | Imagine 4 people living in 3 different houses. How many combinations are there, 40 | and can you list all of them? 41 | 42 | This kind of problem occurs frequently in the real world. 43 | One common property is that the problems contain lots of unknown variables and uncertainties. 44 | Our human brains are poorly adapted to think of many possibilities at once, 45 | but by using computers we can sometimes use brute force. 46 | 47 | Solution: 48 | ``` 49 | 3^4 = 81 50 | 51 | // Each digit position represents a person and the value is where the person lives. 52 | 0000 53 | 0001 54 | 0002 55 | 0010 56 | 0011 57 | 0012 58 | 0020 59 | ... 60 | 3333 61 | ``` 62 | 63 | The discrete space of this kind can be constructed by the type `DimensionN`. 64 | There are 4 dimensions, one for each person, which all has a size of 3. 65 | 66 | ### Discrete spaces can resolve issues with ambiguity of natural language 67 | 68 | Now, consider another problem: 69 | 70 | Imagine 4 couples living in 3 different houses. One house contains maximum 2 couples but no house is empty. 71 | How many combinations are there, and can you list all of them? 72 | 73 | Notice the similarity to the first problem, where people are replaced by couples and 74 | a constraint is added that renders some combinations invalid. 75 | 76 | One approach is to use the same algorithm as in the first problem and filter out 77 | all solutions that does not satisfy the constraints. 78 | Each digit represents a couple instead of a person. 79 | 80 | Another approach is to use 8 people with the same algorithm, 81 | and pick only solutions where a house contains two or four people. 82 | 83 | Both solutions are valid answers, but they answer different questions. 84 | The first approach ignores the arrangement of individuals, while the second approach ignores the arrangement of couples. 85 | How we understand something can depend on which algorithm we use, 86 | but in an informal setting this can be ambiguous. 87 | 88 | A discrete space is a non-ambiguous way to represent all possibilities from the topology and dimension of the solution space. 89 | Each state in the space corresponds to a single location or a sub-structure of a larger problem. 90 | In other words, natural numbers behave as placeholders for something like generic types in programming. 91 | 92 | The structure of the discrete space does not automatically give you the answer, 93 | but it makes it easier to examine a problem from every perspective once you know how to define it. 94 | 95 | One benefit with this approach is that you can start with a low dimension to make sure you understand the problem, 96 | and then expand to the real size of the space of possibilities afterwards. 97 | When a mathematical formula exists for e.g. counting possibilities, 98 | discrete spaces are used to test the first few numbers in the formula. 99 | 100 | Sometimes a large solution space contains symmetries such that it can be contracted to a smaller space. 101 | This can help improve the performance of search and analysis. 102 | When solving problems you are often not aware of these symmetries at first, 103 | but you can start with a general space and then add assumptions of symmetry to make the space smaller. 104 | A technique often used is to split a problem into symmetric parts and asymmetric parts, 105 | such that more efficient algorithms can be used on the simpler cases. 106 | -------------------------------------------------------------------------------- /assets/necklaces.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/advancedresearch/discrete/e2f65af49f564b3a73a0a877e18660366888135c/assets/necklaces.ods -------------------------------------------------------------------------------- /examples/dag.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | A Directed Acyclic Graph (DAG) of `n` nodes is isomorphic to 4 | the upper or lower strictly triangular binary square `n ⨯ n` matrix. 5 | 6 | The discrete space of pairs can be thought of as: 7 | 8 | - (a, b) (a, c) (a, d) 9 | - - (b, c) (b, d) 10 | - - - (c, d) 11 | - - - - 12 | 13 | In a strictly triangular binary square matrix, 14 | these pairs are filled with `0` or `1`. 15 | 16 | Therefore, by taking the powerset of pair, 17 | one can construct a discrete space that is isomorphic to DAGs. 18 | 19 | n count 20 | 1 1 21 | 2 2 22 | 3 8 23 | 4 64 24 | 5 1024 25 | 6 32768 26 | 7 2097152 27 | 8 268435456 28 | 9 68719476736 29 | 10 35184372088832 30 | 11 36028797018963968 31 | 12 73786976294838206464 32 | 13 302231454903657293676544 33 | 14 2475880078570760549798248448 34 | 15 40564819207303340847894502572032 35 | 16 1329227995784915872903807060280344576 36 | 17 87112285931760246646623899502532662132736 37 | 18 11417981541647679048466287755595961091061972992 38 | 19 2993155353253689176481146537402947624255349848014848 39 | 20 1569275433846670190958947355801916604025588861116008628224 40 | 41 | Notice that to count above 11, one needs `BigUint`. 42 | 43 | When enumerating this space, the position is a list of pairs. 44 | 45 | For example: `[(0, 2), (1, 2)]`. 46 | 47 | This means that `2` depends on `0` and `1`. 48 | The DAG can be constructed directly from this data. 49 | 50 | */ 51 | 52 | extern crate discrete; 53 | 54 | use discrete::{ Construct, Count, ToPos, PowerSet, Of, Pair }; 55 | 56 | fn main() { 57 | let n = 3; 58 | let dag: PowerSet> = Construct::new(); 59 | let count = dag.count(&n); 60 | println!("{}", count); 61 | 62 | let mut pos = vec![]; 63 | for i in 0..count { 64 | dag.to_pos(&n, i, &mut pos); 65 | println!("{:?}", pos); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /examples/directed_context.rs: -------------------------------------------------------------------------------- 1 | /* 2 | DIRECTED CONTEXT 3 | 4 | In this example we will try to solve the problem: 5 | 6 | A farmer want to cross a river, using a boat with room for two objects. 7 | With him he has a wolf, a sheep, and some cabbage. 8 | If not watching, the wolf eats the sheep, and the sheep eats the cabbage. 9 | Find an upper bound of legal moves below 200. 10 | 11 | We have 4 objects: Wolf, sheep, cabbage and the boat. 12 | The wolf, sheep and cabbage can be in 3 locations: Side A, boat, side B. 13 | The boat can be in 2 locations: Side A or side B. 14 | This becomes a N-dimensional configuration space of dimensions `[3, 3, 3, 2]`. 15 | 16 | A directed context space models how a configuration space can change by moving 17 | one object into another state at a time. 18 | Each position in the space is equivalent to one move. 19 | 20 | When we construct a directed context space with dimension `[3, 3, 3, 2]`, 21 | we get 378 moves. These are all possible ways the objects can move ignoring 22 | all physical rules. 23 | 24 | There is a rule for context spaces that information that is symmetric 25 | or invariant for one object can be removed without loosing context. 26 | The boat in this case can always move from one side to the other, 27 | regardless the states of other objects. 28 | Therefore, we can reduce the space to `[3, 3, 3]`. 29 | This reduces to 162 moves. 30 | 31 | Each object can only move from side A to side B by using the boat. 32 | We can model a space with dimension `[2, 2, 2, 3]` where the last 33 | dimension tells which item can use the boat. 34 | This reduces to 120 moves. 35 | 36 | A side note: The amount of memory needed to store any rules for such a puzzle 37 | is in worst case 120 bits, because each bit can tell us whether a move is legal 38 | or not. This is the same information we get from rules. 39 | 40 | */ 41 | 42 | extern crate discrete; 43 | 44 | use discrete::*; 45 | 46 | fn main() { 47 | let context: DirectedContext = Construct::new(); 48 | 49 | let dim = vec![2, 2, 2, 3]; 50 | let shorter_count = context.count(&dim); 51 | 52 | let object = ["wolf", "sheep", "cabbage"]; 53 | let side = ["side A", "boat", "side B"]; 54 | let dim = vec![3, 3, 3]; /* wolf, sheep, cabbage, boat */ 55 | let count = context.count(&dim); 56 | for x in 0..count { 57 | let mut pos = (vec![], 0, 0); 58 | context.to_pos(&dim, x, &mut pos); 59 | 60 | println!("{:?}", pos); 61 | print!("the {} ", object[pos.1]); 62 | print!("went from {} ", side[pos.0[pos.1]]); 63 | println!("to {}", side[pos.2]); 64 | 65 | for i in 0..3 { 66 | let pos_state = pos.0[i]; 67 | println!("{} is at {}", object[i], side[pos_state]); 68 | } 69 | } 70 | println!("count {}", count); 71 | 72 | println!("shorter_counter {}", shorter_count); 73 | } 74 | -------------------------------------------------------------------------------- /examples/homotopy.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This example demonstrates the usage of a discrete homotopy space. 4 | 5 | In homotopy theory, one constructs a continuous map between functions. 6 | There can be many different kinds of continuous maps, so spaces get very complex. 7 | It even gets worse by having continuous maps between continuous maps. 8 | Since there is a combinatorial explosion of possibilities, 9 | mathematicians developed techniques to classify these spaces. 10 | One of these techniques is called a "homotopy level". 11 | 12 | Here is an introduction by Vladimir Voedvodsky: https://www.youtube.com/watch?v=E3steS2Hr1Y 13 | 14 | A homotopy level is a way of connecting pieces of a space of a lower homotopy level. 15 | At homotopy level 0, the pieces of the space itself are constructed. 16 | 17 | In a space consisting of a single element, 18 | there exists only one way of connecting it to iself, 19 | therefore at homotopy level 1, there is just one element. 20 | This element represents the path from element in homotopy level 0 to itself. 21 | At homotopy level 2, the paths in homotopy level 1 are connected. 22 | Since there is only one path, there is only one path between paths at level 2. 23 | 24 | However, when you start with 2 elements at homotopy level 0, 25 | there are 3 ways to connect the 2 elements in homotopy level 1: 26 | 27 | 0 ~= 0 0 ~= 1 1 ~= 1 28 | 29 | Here is an overview of the first 6 homotopy levels up to `n=4`: 30 | 31 | level n=0 n=1 n=2 n=3 n=4 32 | 0 0 1 2 3 4 33 | 1 0 1 3 6 10 34 | 2 0 1 6 21 55 35 | 3 0 1 21 231 1540 36 | 4 0 1 231 26796 1186570 37 | 5 0 1 26796 359026206 703974775735 38 | 39 | */ 40 | 41 | extern crate discrete; 42 | 43 | use discrete::*; 44 | use HPoint::*; 45 | 46 | fn main() { 47 | println!("A discrete homotopy space uses `EqPair` internally:"); 48 | let s: EqPair = Construct::new(); 49 | let dim = 4; 50 | let n = s.count(&dim); 51 | println!("dim = {}, count = {}", dim, n); 52 | let mut pos = (0, 0); 53 | for x in 0..n { 54 | s.to_pos(&n, x, &mut pos); 55 | println!("{:?}", pos); 56 | } 57 | println!("================================"); 58 | 59 | println!("Using `EqPair` recursively gives the complexity of homotopy levels:"); 60 | let mut dim = 4; 61 | println!("{}", dim); 62 | for _ in 0..5 { 63 | dim = s.count(&dim); 64 | println!("{}", dim); 65 | } 66 | println!("================================"); 67 | 68 | println!("Another way to construct a homotopy level 2 is to use `EqPair>`:"); 69 | let s: EqPair> = Construct::new(); 70 | let dim = 2; 71 | println!("dim = {}, count = {}", dim, s.count(&dim)); 72 | 73 | println!("Similarly, at homotopy level 3 one can use `EqPair>>>`:"); 74 | let s: EqPair>>> = Construct::new(); 75 | let dim = 2; 76 | println!("dim = {}, count = {}", dim, s.count(&dim)); 77 | 78 | println!("However, for the more general case is it easier to use the `Homotopy` space:"); 79 | let s: Homotopy = Construct::new(); 80 | let level = 2; 81 | let pieces = 2; 82 | let n = s.count(&(level, pieces)); 83 | println!("level = {}, pieces = {}, count = {}", level, pieces, n); 84 | 85 | let mut pos = s.zero(&(level, pieces)); 86 | for x in 0..n { 87 | s.to_pos(&(level, pieces), x, &mut pos); 88 | println!("{:?}", pos); 89 | } 90 | println!("================================"); 91 | 92 | println!("The `HPoint` enum represents positions in the `Homotopy` space:"); 93 | let a = Path(Box::new((Point(0), Point(0)))); 94 | let b = Path(Box::new((Point(1), Point(1)))); 95 | let pos = Path(Box::new((a, b))); 96 | let level = pos.level(); 97 | println!("{:?} - level {}", pos, level); 98 | println!("index = {}", s.to_index(&(level, 2), &pos)); 99 | println!("================================"); 100 | 101 | println!("One can also construct a homotopy of another discrete space, e.g. `Homotopy>`:"); 102 | let s: Homotopy> = Construct::new(); 103 | let level = 1; 104 | let pieces = 3; 105 | let n = s.count(&(level, pieces)); 106 | println!("{}", n); 107 | 108 | let mut pos = s.zero(&(level, pieces)); 109 | for x in 0..n { 110 | s.to_pos(&(level, pieces), x, &mut pos); 111 | println!("{:?}", pos); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /examples/necklace.rs: -------------------------------------------------------------------------------- 1 | /* 2 | A necklace is a group given by a sequence of numbers that can be rotated 3 | left or right, like beads of different colors on a looped string. 4 | 5 | Necklaces are used to describe spaces of objects that can be rotated 6 | around a single axis. 7 | For example, edges between vertices of a 2D triangle are considered the 8 | same no matter how you rotate it. 9 | 10 | Instead of constructing objects the way we intrinsically understand 11 | them in the physical world, the way to do it through discrete mathematics 12 | is to describe some property of the object and then go through the 13 | entire space of possibilities with that property. 14 | Then we filter out the groups we get by equivalence proofs until 15 | we have a set of unique objects with the features we are interested in. 16 | In many cases we can only take a peek into this world, 17 | as long there is no efficient algorithm for either storing or iterate 18 | through complex spaces. 19 | 20 | The algorithm used here prints out the sequence with lowest index, 21 | which represents the local necklace group: 22 | 23 | 1. Generate a map of indices for rotations 24 | 2. Iterate through all n-dimensional sequences 25 | 3. For each sequence, compute rotated sequence 26 | 4. Compute the index of rotated sequence 27 | 5. If rotated sequence has lower index, skip to next sequence 28 | 6. If not, print out sequence 29 | 30 | If the space is very large, only every 100 000 necklace is printed out. 31 | */ 32 | 33 | extern crate discrete; 34 | 35 | use discrete::*; 36 | 37 | fn main() { 38 | let x: DimensionN = Construct::new(); 39 | let n = std::env::args_os().nth(1) 40 | .and_then(|s| s.into_string().ok()) 41 | .and_then(|n| n.parse().ok()) 42 | .unwrap_or(4); 43 | let base = std::env::args_os().nth(2) 44 | .and_then(|s| s.into_string().ok()) 45 | .and_then(|n| n.parse().ok()) 46 | .unwrap_or(3); 47 | println!("n {}, base {}", n, base); 48 | let rot = gen_rotation_map(n); 49 | let ref dim = vec![base; n]; 50 | let count = x.count(dim); 51 | let mut a = vec![0; n]; 52 | let mut b = vec![0; n]; 53 | let mut counter: u64 = 0; 54 | 'i: for i in 0..count { 55 | x.to_pos(dim, i, &mut a); 56 | 57 | for k in 0..rot.len() { 58 | for m in 0..n { 59 | b[m] = a[rot[k][m]]; 60 | } 61 | if x.to_index(dim, &b) < i { continue 'i; } 62 | } 63 | 64 | if count < 500 || counter % 100000 == 0 { 65 | println!("{:?},", a); 66 | } 67 | counter += 1; 68 | } 69 | println!("necklaces {}", counter); 70 | } 71 | 72 | fn gen_rotation_map(n: usize) -> Vec> { 73 | let mut res = vec![]; 74 | for i in 0..n { 75 | let mut row = vec![]; 76 | for j in 0..n { 77 | row.push((j + i) % n); 78 | } 79 | res.push(row) 80 | } 81 | res 82 | } 83 | -------------------------------------------------------------------------------- /examples/pair_of_pairs.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | PAIR OF PAIRS 4 | 5 | In this example we will try to solve the following problem: 6 | 7 | You are a secret MIB agent trying to detect activity of 4 criminal aliens. 8 | The aliens are of species that live in pairs and die if separated by 10m. 9 | You know that the 4 criminal aliens met each other at some point, 10 | but not when or where. 11 | 12 | A super computer is monitoring all the people in a city. 13 | Each person has a unique identity. 14 | Unfortunately, the computer's AI refuses to collaborate of ethical reasons, 15 | and the super computer can therefore only tell you yes/no questions. 16 | 17 | If the city contains N people, find all possible meetups of pairs. 18 | 19 | Notice that a person can not meet itself, and even if the alien species 20 | can time travel they always occur in the same pair. 21 | 22 | Using this library, we can construct a discrete space that contains all 23 | combinations of pairs. Not only can we get all pairs of up to N objects, 24 | but we can also construct a space containing pair of pairs. 25 | 26 | We simply create a variable of type `Pair>>` and call 27 | `Construct::new()` to create it. 28 | 29 | The Rust compiler can now assist you solving rest of the task. 30 | 31 | For every space, there is a dimension type and a position type. 32 | The dimension type is needed to control the size of the space. 33 | In our case the dimension type is a number N. 34 | The position type is a structure that describes the data within the space. 35 | 36 | Discrete spaces have the property that each number from 0 up to the size 37 | corresponds to position within the space. It is the information inside 38 | the position we are interested in, because plain numbers are meaningless. 39 | The `ToPos` trait converts from a number to the position structure. 40 | 41 | By computing the size of the space and iterating through every number, 42 | we can convert it to a position and then do filtering based on some criteria. 43 | In our case we can filter out any meetups between pairs where one person 44 | is in both pairs. 45 | 46 | For example, for 150 people there are 61 332 125 possible meetups. 47 | 48 | */ 49 | 50 | extern crate discrete; 51 | 52 | use discrete::{ Count, Construct, Pair, Of, Data, ToPos }; 53 | 54 | fn main() { 55 | let pair_of_pairs: Pair>> = Construct::new(); 56 | let ref n = 150; 57 | let count = pair_of_pairs.count(n); 58 | println!("count {:?}", count); 59 | let mut pos: ((usize, usize), (usize, usize)) = ((0, 0), (0, 0)); 60 | let mut res_count = 0; 61 | for x in 0..count { 62 | pair_of_pairs.to_pos(n, x, &mut pos); 63 | if (pos.0).0 == (pos.1).0 64 | || (pos.0).0 == (pos.1).1 65 | || (pos.0).1 == (pos.1).0 { 66 | // println!("anomaly {:?}", pos) 67 | } else { 68 | // println!("{:?}", pos); 69 | res_count += 1; 70 | } 71 | } 72 | println!("{:?} results", res_count); 73 | } 74 | -------------------------------------------------------------------------------- /examples/pair_of_powersets.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | PAIR OF POWERSETS 4 | 5 | In this example we will try to solve the following problem: 6 | 7 | Alice is fishing, and she knows of 10 fish species in the ocean. 8 | After 2 hours, Alice caught 4 different species. 9 | 10 | As she watches the sunset, she wonders how many possible worlds 11 | she could catch exactly 4 species out of the unknown number of 12 | species that lives in this particular area. 13 | 14 | A powerset is a way to describe how many ways you can pick things. 15 | Because Alice is fishing, she is picking fish species from the ocean. 16 | We can also think of the species living in this area as being "picked" 17 | from the species that lives in the ocean in general. 18 | 19 | A pair can be described with a tuple `(a, b)` where `b` is greater than `a`. 20 | Because Alice can't catch other species than those who lives in the area, 21 | we can think of the species living nearby as a powerset, paired with 22 | a powerset that Alice catches. 23 | 24 | Alice might catch all the species living nearby, while a pair 25 | excludes tuples of the kind `(a, a)`. Therefore, instead of `Pair` we'll use 26 | `EqPair`. 27 | 28 | A pair of power sets can contain sets that are not subsets of another. 29 | We have to eliminate those by checking for subsets, such that Alice 30 | doesn't catch fishes that doesn't live in the nearby area. 31 | 32 | When we print out the number of pairs of power sets of N where one is subset of 33 | another, we get a familiar sequence: 34 | 35 | N = 0: 1 36 | N = 1: 3 37 | N = 2: 9 38 | N = 3: 27 39 | N = 4: 81 40 | 41 | If the number of fishes in the ocean are `N`, then the number of worlds 42 | Alice can catch fishes nearby is `3^N`. Among the 10 species in the ocean, 43 | there are 59049 kinds of worlds. 44 | 45 | Last, we need to filter out the worlds where Alice doesn't catch 4 species. 46 | 47 | There are exactly 13440 such worlds, and we can list all of them. 48 | 49 | */ 50 | 51 | extern crate discrete; 52 | 53 | use discrete::*; 54 | 55 | fn main() { 56 | let pair_of_powersets: EqPair>> = Construct::new(); 57 | let ref n = 10; 58 | let count = pair_of_powersets.count(n); 59 | println!("count {:?}", count); 60 | let mut pos: (Vec, Vec) = (Vec::new(), Vec::new()); 61 | let mut res_count = 0; 62 | for x in 0..count { 63 | pair_of_powersets.to_pos(n, x, &mut pos); 64 | // Ignore worlds where Alice doesn't catch 4 species. 65 | if (pos.0).len() != 4 { continue; } 66 | let mut subset = true; 67 | for a in (pos.0).iter() { 68 | let mut found = false; 69 | for b in (pos.1).iter() { 70 | if a == b { found = true; break; } 71 | } 72 | if !found { subset = false; break; } 73 | } 74 | if subset { 75 | println!("{:?}", pos); 76 | res_count += 1; 77 | } 78 | } 79 | println!("{:?}", res_count); 80 | } 81 | -------------------------------------------------------------------------------- /examples/sq_pair.rs: -------------------------------------------------------------------------------- 1 | extern crate discrete; 2 | 3 | use discrete::*; 4 | 5 | fn main() { 6 | println!("One way to create a square of pairs is using `(Dimension, Dimension):`"); 7 | let s: (Dimension, Dimension) = Construct::new(); 8 | println!("{}", s.count(&(2, 2))); 9 | 10 | println!("Another way is to use `DimensionN`:"); 11 | let s: DimensionN = Construct::new(); 12 | println!("{}", s.count(&vec![2, 2])); 13 | 14 | println!("Or, to avoid needing specifying the dimension twice, one can use `SqPair`:"); 15 | let s: SqPair = Construct::new(); 16 | println!("{}", s.count(&2)); 17 | 18 | let mut p = s.zero(&2); 19 | for i in 0..4 { 20 | s.to_pos(&2, i, &mut p); 21 | println!("{:?}", p); 22 | } 23 | 24 | println!("One can also create a square of another discrete space, e.g. `SqPair>`:"); 25 | let s: SqPair> = Construct::new(); 26 | let n = 3; 27 | let count = s.count(&n); 28 | println!("{}", count); 29 | 30 | let mut p = s.zero(&n); 31 | for i in 0..count { 32 | s.to_pos(&n, i, &mut p); 33 | println!("{:?}", p); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/test.rs: -------------------------------------------------------------------------------- 1 | extern crate discrete; 2 | 3 | use discrete::*; 4 | 5 | fn main() { 6 | let s: Pair>>> = Construct::new(); 7 | let dim: BigUint = 2usize.into(); 8 | 9 | let dim = dim.pow(1); 10 | let count = s.count(&dim); 11 | 12 | let mut i: BigUint = count.clone() - 1usize; 13 | let mut pos = s.zero(&dim); 14 | let mut j = 0; 15 | let z: BigUint = 0usize.into(); 16 | while i >= z { 17 | if j > 3 {break}; 18 | 19 | s.to_pos(&dim, i.clone(), &mut pos); 20 | println!("{}: {:?}", i, pos); 21 | 22 | i -= 1usize; 23 | j += 1; 24 | } 25 | 26 | println!("{}", count); 27 | } 28 | -------------------------------------------------------------------------------- /examples/triangle_cycles.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Finds the 16 triangle cycles on a square. 4 | 5 | */ 6 | 7 | extern crate discrete; 8 | 9 | use discrete::*; 10 | 11 | fn main() { 12 | let s: Permutation> = Construct::new(); 13 | let dim = 4; 14 | let mut pos = s.zero(&dim); 15 | println!("Structure: {:?}\n", pos); 16 | let count = s.count(&dim); 17 | let mut triangles = 0; 18 | // Exploits that the extra 3 pairs are permuted 19 | // right to left, so one can skip to every 6th solution. 20 | let scale = 6; 21 | for i in 0..count/scale { 22 | let i = i * scale; 23 | s.to_pos(&dim, i, &mut pos); 24 | let triangle = connected(pos[0], pos[1]) && 25 | connected(pos[1], pos[2]) && 26 | connected(pos[2], pos[0]); 27 | let tri = &pos[0..3]; 28 | let non_rotated = min_pair(tri, |pos| { 29 | let s: Pair = Construct::new(); 30 | s.to_index(&dim, &pos) 31 | }) == Some(0); 32 | if triangle && non_rotated { 33 | triangles += 1; 34 | println!("{:?}", tri); 35 | } 36 | } 37 | println!("{:?} => {}", dim, count); 38 | println!("triangles {}", triangles); 39 | } 40 | 41 | pub fn connected(a: (usize, usize), b: (usize, usize)) -> bool { 42 | a.0 == b.0 || 43 | a.1 == b.0 || 44 | a.0 == b.1 || 45 | a.1 == b.1 46 | } 47 | 48 | pub fn min_pair(ps: &[(usize, usize)], to_index: impl Fn((usize, usize)) -> usize) -> Option { 49 | ps.iter().map(|&n| to_index(n)).enumerate().min_by_key(|(_, j)| *j).map(|(i, _)| i) 50 | } 51 | -------------------------------------------------------------------------------- /examples/world_agent.rs: -------------------------------------------------------------------------------- 1 | /* 2 | WORLD - AGENT 3 | 4 | In this example will we try to solve the following problem: 5 | 6 | A an AI agent has a mode and a goal. 7 | The mode consists of 3 states: Happy, Sad and Angry. 8 | The goal consists of 2 states: BeGood and BeBad. 9 | The world is a grid consisting of 4x4 squares. 10 | The agent can move up, right, down or left. 11 | Find a way to enumerate all changes of states, 12 | whether it is a different mood, a different goal, 13 | or a different position in the world. 14 | 15 | A directed context space can be used to describe changes of states. 16 | First, we figure out how to encode moods and goals. 17 | 18 | If we use the dimensions `[mood, goal]`, which are 18 states, 19 | then we don't know where the agent is or which direction it will go. 20 | 21 | If we use the dimensions `[mood, goal, direction]`, which are 144 states, 22 | then we get duplicates because we do not want to know change of direction. 23 | 24 | So, there is a trick: 25 | Instead of changing direction, we add a direction "go nowhere". 26 | This means get 5 directions, but it can be factored out into a dimension. 27 | 28 | What we got now is `([mood, goal], direction)`. 29 | It gives us 90 states. 30 | 31 | However, for every change in mode or goal, there is now all directions. 32 | We would like to remove this redundancy, so there is either 33 | a change in mode or goal, or direction. 34 | 35 | Again, there is a trick: 36 | By using `([mood, goal, 2], direction/2)` with the original 4 directions, 37 | there is a change `0 -> 1` and `1 -> 0` in the directed context space. 38 | This bit tells us whether to use `up/down` or `right/left`. 39 | It means we need only to pick between the other two in the dimension. 40 | 41 | However, this gives us 96 states, which is worse than before. 42 | The reason is that there are two direction bits for every change in 43 | mood or goal when we only need one. 44 | 45 | So, we need to select between `[mood, goal]` or `direction`. 46 | However, we need to keep the `mood` and `goal` state when going in a direction. 47 | This means we have to select either `{[mood, goal], [mood, goal, direction]}`. 48 | The first option is a directed context space, 49 | while the second option is an N-dimensional space. 50 | 51 | To do this one can use the `Either` space. 52 | This reduces the number of states to 42. 53 | 54 | Finally, we put the grid inside a N-dimensional space: 55 | ({[mood, goal], [mood, goal, direction]}, [4, 4]) 56 | 57 | This gives us a total of 672 states. 58 | 59 | */ 60 | 61 | extern crate discrete; 62 | 63 | use discrete::*; 64 | 65 | fn main() { 66 | let mood = 3; 67 | let goal = 2; 68 | let direction = 4; 69 | 70 | let context: (Either, DimensionN) = Construct::new(); 71 | let dim = ((vec![mood, goal], vec![mood, goal, direction]), vec![4, 4]); 72 | let count = context.count(&dim); 73 | println!("count: {:?}", count); 74 | 75 | let mut pos = (Select::Fst((vec![0, 0], 1, 1)), vec![0, 0]); 76 | // println!(" {:?}", context.to_index(&dim, &pos)); 77 | for x in 0..5 { 78 | context.to_pos(&dim, x, &mut pos); 79 | println!("\n{}/{} {}% {:?}", x, count, (100.0 * (x as f64) / (count as f64)).round(), pos); 80 | desc(&pos); 81 | } 82 | } 83 | 84 | fn desc(pos: &(Select<(Vec, usize, usize), Vec>, Vec)) { 85 | let (mood, goal, change, new_value, direction) = match pos.0 { 86 | Select::Fst(ref pos) => (pos.0[0], pos.0[1], pos.1, pos.2, None), 87 | Select::Snd(ref pos) => (pos[0], pos[1], 2, pos[2], Some(pos[2])), 88 | }; 89 | 90 | let x = pos.1[0]; 91 | let y = pos.1[1]; 92 | print!("Mood: "); 93 | desc_mood(mood); 94 | print!("Goal: "); 95 | desc_goal(goal); 96 | if let Some(direction) = direction { 97 | desc_direction(direction); 98 | } 99 | if change == 0 { 100 | print!("Change mood to: "); 101 | desc_mood(new_value); 102 | } else if change == 1 { 103 | print!("Change goal to: "); 104 | desc_goal(new_value); 105 | } 106 | println!("Position: ({}, {})", x, y); 107 | } 108 | 109 | fn desc_mood(mood: usize) { 110 | match mood { 111 | 0 => println!("Happy"), 112 | 1 => println!("Sad"), 113 | 2 => println!("Angry"), 114 | _ => {} 115 | } 116 | } 117 | 118 | fn desc_goal(goal: usize) { 119 | match goal { 120 | 0 => println!("BeGood"), 121 | 1 => println!("BeBad"), 122 | _ => {} 123 | } 124 | } 125 | 126 | fn desc_direction(direction: usize) { 127 | print!("Change position: "); 128 | match direction { 129 | 0 => println!("go up"), 130 | 1 => println!("go right"), 131 | 2 => println!("go down"), 132 | 3 => println!("go left"), 133 | _ => {} 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/construct.rs: -------------------------------------------------------------------------------- 1 | /// Constructs a new space. 2 | /// 3 | /// Since spaces are combined using phantom types, 4 | /// an instance must be constructed to call methods on it. 5 | pub trait Construct { 6 | /// Constructs a new Self. 7 | fn new() -> Self; 8 | } 9 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::marker::PhantomData; 3 | use std::ops::{ 4 | Add, 5 | Div, 6 | Mul, 7 | MulAssign, 8 | SubAssign, 9 | DivAssign, 10 | Sub, 11 | AddAssign, 12 | }; 13 | 14 | use num::BigUint; 15 | 16 | use Construct; 17 | use Data; 18 | use Of; 19 | use Pair; 20 | use space::Space; 21 | 22 | /// A discrete space that can model spatial operations over arbitrary states, 23 | /// therefore useful for context analysis. 24 | /// 25 | /// It can be constructed by taking a N-dimensional space, 26 | /// for each dimension create a pair subspace and sum over the dimensions. 27 | /// It can also be thought of as the edges in an undirected graph, 28 | /// where each node is described by a N-dimensional coordinate, 29 | /// and all nodes are connected which differ by one axis. 30 | /// 31 | /// Dimensions of size 2 gives the edges on a hypercube of the number of dimensions. 32 | /// For example, `[2, 2, 2]` gives edges on a cube in 3 dimensions. 33 | /// 34 | /// The position is a tuple `(Vec, usize, usize)`, 35 | /// where the first component describes the node coordinates, 36 | /// the second component describes the index of the coordinate that changes, 37 | /// and the third component describes the new value. 38 | pub struct Context(PhantomData); 39 | 40 | /// Computes subspace offset from which index that changes. 41 | /// The space is divided into N subspaces, 42 | /// because only one axis can change at a time. 43 | /// 44 | /// ```ignore 45 | /// [(a, x), b, c] 46 | /// [a, (b, x), c] 47 | /// [a, b, (c, x)] 48 | /// ``` 49 | fn subspace_offset(v: &[usize], ind: usize) -> usize { 50 | let pair: Pair = Construct::new(); 51 | let mut sum = 0; 52 | for i in 0..ind { 53 | let mut prod = 1; 54 | for j in 0..v.len() { 55 | if i == j { continue; } 56 | prod *= v[j]; 57 | } 58 | sum += >::count(&pair, &v[i]) * prod; 59 | } 60 | sum 61 | } 62 | 63 | /// Computes subspace offset from which index that changes. 64 | /// The space is divided into N subspaces, 65 | /// because only one axis can change at a time. 66 | /// 67 | /// ```ignore 68 | /// [(a, x), b, c] 69 | /// [a, (b, x), c] 70 | /// [a, b, (c, x)] 71 | /// ``` 72 | fn biguint_subspace_offset(v: &[BigUint], ind: usize) -> BigUint { 73 | let pair: Pair = Construct::new(); 74 | let mut sum: BigUint = 0usize.into(); 75 | for i in 0..ind { 76 | let mut prod: BigUint = 1usize.into(); 77 | for j in 0..v.len() { 78 | if i == j { continue; } 79 | prod *= &v[j]; 80 | } 81 | sum += >::count(&pair, &v[i]) * prod; 82 | } 83 | sum 84 | } 85 | 86 | /// Computes the index of the axis that changes from index position. 87 | /// This works because the layout are separated by which 88 | /// axis that changes, and the subspace offset can be computed. 89 | /// Returns `(ind, offset)` 90 | fn ind_from_index(v: &[usize], index: usize) -> (usize, usize) { 91 | let pair: Pair = Construct::new(); 92 | let mut sum = 0; 93 | for i in 0..v.len() { 94 | let mut prod = 1; 95 | for j in 0..v.len() { 96 | if i == j { continue; } 97 | prod *= v[j]; 98 | } 99 | let add = >::count(&pair, &v[i]) * prod; 100 | if sum + add > index { return (i, sum); } 101 | sum += add; 102 | } 103 | (v.len(), sum) 104 | } 105 | 106 | /// Computes the index of the axis that changes from index position. 107 | /// This works because the layout are separated by which 108 | /// axis that changes, and the subspace offset can be computed. 109 | /// Returns `(ind, offset)` 110 | fn biguint_ind_from_index(v: &[BigUint], index: &BigUint) -> (usize, BigUint) { 111 | let pair: Pair = Construct::new(); 112 | let mut sum: BigUint = 0usize.into(); 113 | for i in 0..v.len() { 114 | let mut prod: BigUint = 1usize.into(); 115 | for j in 0..v.len() { 116 | if i == j { continue; } 117 | prod *= &v[j]; 118 | } 119 | let add = >::count(&pair, &v[i]) * prod; 120 | if &(&sum + &add) > index { return (i, sum); } 121 | sum += add; 122 | } 123 | (v.len(), sum) 124 | } 125 | 126 | 127 | impl Construct for Context { 128 | fn new() -> Context { Context(PhantomData) } 129 | } 130 | 131 | impl Space for Context { 132 | type Dim = Vec; 133 | type Pos = (Vec, usize, usize); 134 | fn count(&self, dim: &Vec) -> usize { 135 | let pair: Pair = Construct::new(); 136 | let mut sum: usize = pair.count(&dim[0]); 137 | let mut prod = dim[0]; 138 | for d in &dim[1..] { 139 | let count: usize = pair.count(d); 140 | sum = d * sum + count * prod; 141 | prod *= *d; 142 | } 143 | sum 144 | } 145 | fn zero(&self, dim: &Vec) -> (Vec, usize, usize) { 146 | (vec![0; dim.len()], 0, 0) 147 | } 148 | fn to_index( 149 | &self, 150 | dim: &Vec, 151 | &(ref p, ind, b): &(Vec, usize, usize) 152 | ) -> usize { 153 | use std::cmp::{ min, max }; 154 | 155 | let offset = subspace_offset(dim, ind); 156 | let pair: Pair = Construct::new(); 157 | let mut prod = 1; 158 | for j in 0..dim.len() { 159 | if ind == j { continue; } 160 | prod *= dim[j]; 161 | } 162 | // Pair doesn't care about dimension. 163 | let single: usize = pair.to_index(&0, &(min(p[ind], b), max(p[ind], b))); 164 | let pos_offset: usize = single * prod; 165 | let mut dim_index = 0; 166 | for i in (0..p.len()).rev() { 167 | if ind == i { continue; } 168 | dim_index = dim_index * dim[i] + p[i]; 169 | } 170 | offset + pos_offset + dim_index 171 | } 172 | fn to_pos( 173 | &self, 174 | dim: &Vec, 175 | index: usize, 176 | &mut (ref mut p, ref mut ind, ref mut b): &mut (Vec, usize, usize) 177 | ) { 178 | p.clear(); 179 | let pair_space: Pair = Construct::new(); 180 | let (ind_val, offset) = ind_from_index(dim, index); 181 | // Get rid of offset. 182 | // The rest equals: single * prod + dim_index 183 | let index = index - offset; 184 | let mut prod = 1; 185 | for j in 0..dim.len() { 186 | p.push(0); // zero position 187 | if ind_val == j { continue; } 188 | prod *= dim[j]; 189 | } 190 | let single = index / prod; 191 | 192 | let mut pair = (0, 0); 193 | // Pair doesn't care about dimension. 194 | pair_space.to_pos(&0, single, &mut pair); 195 | let (min, max) = pair; 196 | 197 | // Resolve other dimension components. 198 | let mut dim_index = index - single * prod; 199 | for i in (0..p.len()).rev() { 200 | if ind_val == i { continue; } 201 | prod /= dim[i]; 202 | let p_i = dim_index / prod; 203 | p[i] = p_i; 204 | dim_index -= p_i * prod; 205 | } 206 | p[ind_val] = min; 207 | *b = max; 208 | *ind = ind_val; 209 | } 210 | } 211 | 212 | impl Space for Context { 213 | type Dim = Vec; 214 | type Pos = (Vec, usize, BigUint); 215 | fn count(&self, dim: &Vec) -> BigUint { 216 | let pair: Pair = Construct::new(); 217 | let mut sum: BigUint = pair.count(&dim[0]); 218 | let mut prod = dim[0].clone(); 219 | for d in &dim[1..] { 220 | let count: BigUint = pair.count(d); 221 | sum = d * sum + count * ∏ 222 | prod *= d; 223 | } 224 | sum 225 | } 226 | fn zero(&self, dim: &Vec) -> (Vec, usize, BigUint) { 227 | (vec![0usize.into(); dim.len()], 0, 0usize.into()) 228 | } 229 | fn to_index( 230 | &self, 231 | dim: &Self::Dim, 232 | (p, ind, b): &Self::Pos, 233 | ) -> BigUint { 234 | use std::cmp::{ min, max }; 235 | 236 | let ind = *ind; 237 | let offset = biguint_subspace_offset(dim, ind); 238 | let pair: Pair = Construct::new(); 239 | let mut prod: BigUint = 1usize.into(); 240 | for j in 0..dim.len() { 241 | if ind == j { continue; } 242 | prod *= &dim[j]; 243 | } 244 | // Pair doesn't care about dimension. 245 | let single: BigUint = pair.to_index(&0usize.into(), &(min(p[ind].clone(), b.clone()), max(p[ind].clone(), b.clone()))); 246 | let pos_offset: BigUint = single * prod; 247 | let mut dim_index: BigUint = 0usize.into(); 248 | for i in (0..p.len()).rev() { 249 | if ind == i { continue; } 250 | dim_index = dim_index * &dim[i] + &p[i]; 251 | } 252 | offset + pos_offset + dim_index 253 | } 254 | fn to_pos( 255 | &self, 256 | dim: &Self::Dim, 257 | index: BigUint, 258 | &mut (ref mut p, ref mut ind, ref mut b): &mut (Vec, usize, BigUint) 259 | ) { 260 | p.clear(); 261 | let pair_space: Pair = Construct::new(); 262 | let (ind_val, offset) = biguint_ind_from_index(dim, &index); 263 | // Get rid of offset. 264 | // The rest equals: single * prod + dim_index 265 | let index = index - &offset; 266 | let mut prod: BigUint = 1usize.into(); 267 | for j in 0..dim.len() { 268 | p.push(0usize.into()); // zero position 269 | if ind_val == j { continue; } 270 | prod *= &dim[j]; 271 | } 272 | let single = &index / ∏ 273 | 274 | let mut pair: (BigUint, BigUint) = (0usize.into(), 0usize.into()); 275 | // Pair doesn't care about dimension. 276 | let z: BigUint = 0usize.into(); 277 | pair_space.to_pos(&z, single.clone(), &mut pair); 278 | let (min, max) = pair; 279 | 280 | // Resolve other dimension components. 281 | let mut dim_index = index - &single * ∏ 282 | for i in (0..p.len()).rev() { 283 | if ind_val == i { continue; } 284 | prod /= &dim[i]; 285 | let p_i = &dim_index / ∏ 286 | dim_index -= &p_i * ∏ 287 | p[i] = p_i; 288 | } 289 | p[ind_val] = min; 290 | *b = max; 291 | *ind = ind_val; 292 | } 293 | } 294 | 295 | impl Space for Context> 296 | where T: Space, 297 | Pair: Space, 298 | for<'a> N: Clone + 299 | From + 300 | Ord + 301 | MulAssign<&'a N> + 302 | SubAssign<&'a N> + 303 | DivAssign<&'a N> + 304 | AddAssign<&'a N>, 305 | for<'a> &'a N: Mul<&'a N, Output = N> + 306 | Div<&'a N, Output = N> + 307 | Add<&'a N, Output = N> + 308 | Sub<&'a N, Output = N>, 309 | { 310 | type Dim = Vec; 311 | type Pos = (Vec, usize, T::Pos); 312 | fn count(&self, dim: &Self::Dim) -> N { 313 | let of: T = Construct::new(); 314 | let pair: Pair = Construct::new(); 315 | let mut sum: N = pair.count(&of.count(&dim[0])); 316 | let mut prod = of.count(&dim[0]); 317 | for d in &dim[1..] { 318 | let d: N = of.count(d); 319 | let count: N = pair.count(&d); 320 | sum = &(&d * &sum) + &(&count * &prod); 321 | prod *= &d; 322 | } 323 | sum 324 | } 325 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 326 | let of: T = Construct::new(); 327 | let mut v = Vec::with_capacity(dim.len()); 328 | for i in 0..dim.len() { 329 | v.push(of.zero(&dim[i])); 330 | } 331 | (v, 0, of.zero(&dim[0])) 332 | } 333 | fn to_index( 334 | &self, 335 | dim: &Self::Dim, 336 | &(ref p, ind, ref b): &Self::Pos 337 | ) -> N { 338 | fn subspace_offset(v: &Vec, ind: usize) -> N 339 | where T: Space, 340 | Pair: Space, 341 | for<'a> N: From + 342 | AddAssign<&'a N> + 343 | MulAssign<&'a N>, 344 | for<'a> &'a N: Mul<&'a N, Output = N>, 345 | { 346 | let of: T = Construct::new(); 347 | let pair: Pair = Construct::new(); 348 | let mut sum: N = 0usize.into(); 349 | for i in 0..ind { 350 | let mut prod: N = 1usize.into(); 351 | for j in 0..v.len() { 352 | if i == j { continue; } 353 | prod *= &of.count(&v[j]); 354 | } 355 | let c: N = pair.count(&of.count(&v[i])); 356 | sum += &(&c * &prod); 357 | } 358 | sum 359 | } 360 | 361 | use std::cmp::{ min, max }; 362 | 363 | let of: T = Construct::new(); 364 | let offset = subspace_offset::(dim, ind); 365 | let pair: Pair = Construct::new(); 366 | let mut prod: N = 1usize.into(); 367 | for j in 0..dim.len() { 368 | if ind == j { continue; } 369 | prod *= &of.count(&dim[j]); 370 | } 371 | // Pair doesn't care about dimension. 372 | let single = pair.to_index(&0usize.into(), 373 | &(min(of.to_index(&dim[ind], &p[ind]), of.to_index(&dim[ind], b)), 374 | max(of.to_index(&dim[ind], &p[ind]), of.to_index(&dim[ind], b)))); 375 | let pos_offset = &(&single * &prod); 376 | let mut dim_index: N = 0usize.into(); 377 | for i in (0..p.len()).rev() { 378 | if ind == i { continue; } 379 | dim_index = &(&dim_index * &of.count(&dim[i])) + &of.to_index(&dim[i], &p[i]); 380 | } 381 | &(&offset + &pos_offset) + &dim_index 382 | } 383 | fn to_pos( 384 | &self, 385 | dim: &Self::Dim, 386 | index: N, 387 | &mut (ref mut p, ref mut ind, ref mut b): &mut Self::Pos 388 | ) { 389 | fn ind_from_index(v: &Vec, index: &N) -> (usize, N) 390 | where T: Space, 391 | Pair: Space, 392 | for<'a> N: From + 393 | PartialOrd + 394 | AddAssign<&'a N> + 395 | MulAssign<&'a N>, 396 | for<'a> &'a N: Add<&'a N, Output = N> + 397 | Mul<&'a N, Output = N>, 398 | { 399 | let of: T = Construct::new(); 400 | let pair: Pair = Construct::new(); 401 | let mut sum: N = 0usize.into(); 402 | for i in 0..v.len() { 403 | let mut prod: N = 1usize.into(); 404 | for j in 0..v.len() { 405 | if i == j { continue; } 406 | prod *= &of.count(&v[j]); 407 | } 408 | let c: N = pair.count(&of.count(&v[i])); 409 | let add: N = &c * ∏ 410 | if &(&sum + &add) > index { return (i, sum); } 411 | sum += &add; 412 | } 413 | (v.len(), sum) 414 | } 415 | 416 | let of: T = Construct::new(); 417 | p.clear(); 418 | let pair_space: Pair = Construct::new(); 419 | let (ind_val, offset) = ind_from_index::(dim, &index); 420 | // Get rid of offset. 421 | // The rest equals: single * prod + dim_index 422 | let index: N = &index - &offset; 423 | let mut prod: N = 1usize.into(); 424 | for j in 0..dim.len() { 425 | p.push(of.zero(&dim[j])); // zero position 426 | if ind_val == j { continue; } 427 | prod *= &of.count(&dim[j]); 428 | } 429 | let single: N = &index / ∏ 430 | 431 | let mut pair = (0usize.into(), 0usize.into()); 432 | // Pair doesn't care about dimension. 433 | pair_space.to_pos(&0usize.into(), single.clone(), &mut pair); 434 | let (min, max) = pair; 435 | 436 | // Resolve other dimension components. 437 | let mut dim_index: N = &index - &(&single * &prod); 438 | for i in (0..p.len()).rev() { 439 | if ind_val == i { continue; } 440 | prod /= &of.count(&dim[i]); 441 | let p_i = &dim_index / ∏ 442 | dim_index -= &(&p_i * &prod); 443 | of.to_pos(&dim[i], p_i, &mut p[i]); 444 | } 445 | of.to_pos(&dim[ind_val], min, &mut p[ind_val]); 446 | of.to_pos(&dim[ind_val], max, b); 447 | *ind = ind_val; 448 | } 449 | } 450 | 451 | #[cfg(test)] 452 | mod tests { 453 | use crate::*; 454 | 455 | #[test] 456 | fn features() { 457 | is_complete::(); 458 | is_complete::>>(); 459 | } 460 | 461 | #[test] 462 | fn data() { 463 | let x: Context = Construct::new(); 464 | let ref dim = vec![2usize, 2, 2]; 465 | // 12 edges on a cube 466 | assert_eq!(x.count(dim), 12); 467 | assert_eq!(x.to_index(dim, &(vec![0, 0, 0], 0, 1)), 0); 468 | for i in 0..x.count(dim) { 469 | let mut pos = (vec![], 0, 0); 470 | x.to_pos(dim, i, &mut pos); 471 | assert_eq!(x.to_index(dim, &pos), i); 472 | } 473 | } 474 | 475 | #[test] 476 | fn data_big() { 477 | use std::convert::TryInto; 478 | 479 | let x: Context = Construct::new(); 480 | let ref dim: Vec = vec![2usize.into(), 2usize.into(), 2usize.into()]; 481 | // 12 edges on a cube 482 | assert_eq!(x.count(dim), 12usize.into()); 483 | assert_eq!(x.to_index(dim, &x.zero(dim)), 0usize.into()); 484 | let count = x.count(dim).try_into().unwrap(); 485 | for i in 0usize..count { 486 | let i: BigUint = i.into(); 487 | let mut pos = x.zero(dim); 488 | x.to_pos(dim, i.clone(), &mut pos); 489 | assert_eq!(x.to_index(dim, &pos), i); 490 | } 491 | } 492 | 493 | #[test] 494 | fn of() { 495 | let x: Context> = Construct::new(); 496 | let ref dim = vec![3]; 497 | assert_eq!(x.count(dim), 3); 498 | assert_eq!(x.to_index(dim, &(vec![(0, 1)], 0, (0, 2))), 0); 499 | assert_eq!(x.to_index(dim, &(vec![(0, 1)], 0, (1, 2))), 1); 500 | assert_eq!(x.to_index(dim, &(vec![(0, 2)], 0, (1, 2))), 2); 501 | let ref dim = vec![3, 3]; 502 | assert_eq!(x.count(dim), 18); 503 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 1)], 0, (0, 2))), 0); 504 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 2)], 0, (0, 2))), 1); 505 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (1, 2)], 0, (0, 2))), 2); 506 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 1)], 0, (1, 2))), 3); 507 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 2)], 0, (1, 2))), 4); 508 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (1, 2)], 0, (1, 2))), 5); 509 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (0, 1)], 0, (1, 2))), 6); 510 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (0, 2)], 0, (1, 2))), 7); 511 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (1, 2)], 0, (1, 2))), 8); 512 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 1)], 1, (0, 2))), 9); 513 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (0, 1)], 1, (0, 2))), 10); 514 | assert_eq!(x.to_index(dim, &(vec![(1, 2), (0, 1)], 1, (0, 2))), 11); 515 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 1)], 1, (1, 2))), 12); 516 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (0, 1)], 1, (1, 2))), 13); 517 | assert_eq!(x.to_index(dim, &(vec![(1, 2), (0, 1)], 1, (1, 2))), 14); 518 | assert_eq!(x.to_index(dim, &(vec![(0, 1), (0, 2)], 1, (1, 2))), 15); 519 | assert_eq!(x.to_index(dim, &(vec![(0, 2), (0, 2)], 1, (1, 2))), 16); 520 | assert_eq!(x.to_index(dim, &(vec![(1, 2), (0, 2)], 1, (1, 2))), 17); 521 | 522 | let mut pos = (vec![(0, 0), (0, 0)], 0, (0, 0)); 523 | x.to_pos(dim, 16, &mut pos); 524 | assert_eq!(pos, ((vec![(0, 2), (0, 2)], 1, (1, 2)))); 525 | } 526 | 527 | #[test] 528 | fn of_big() { 529 | fn conv((x, i, (a, b)): (Vec<(usize, usize)>, usize, (usize, usize))) -> (Vec<(BigUint, BigUint)>, usize, (BigUint, BigUint)) { 530 | (x.into_iter().map(|(n, m)| (n.into(), m.into())).collect(), i, (a.into(), b.into())) 531 | } 532 | 533 | let x: Context> = Construct::new(); 534 | let ref dim: Vec = vec![3usize.into()]; 535 | assert_eq!(x.count(dim), 3usize.into()); 536 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1)], 0, (0, 2)))), 0usize.into()); 537 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1)], 0, (1, 2)))), 1usize.into()); 538 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2)], 0, (1, 2)))), 2usize.into()); 539 | let ref dim: Vec = vec![3usize.into(), 3usize.into()]; 540 | assert_eq!(x.count(dim), 18usize.into()); 541 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 1)], 0, (0, 2)))), 0usize.into()); 542 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 2)], 0, (0, 2)))), 1usize.into()); 543 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (1, 2)], 0, (0, 2)))), 2usize.into()); 544 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 1)], 0, (1, 2)))), 3usize.into()); 545 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 2)], 0, (1, 2)))), 4usize.into()); 546 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (1, 2)], 0, (1, 2)))), 5usize.into()); 547 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (0, 1)], 0, (1, 2)))), 6usize.into()); 548 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (0, 2)], 0, (1, 2)))), 7usize.into()); 549 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (1, 2)], 0, (1, 2)))), 8usize.into()); 550 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 1)], 1, (0, 2)))), 9usize.into()); 551 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (0, 1)], 1, (0, 2)))), 10usize.into()); 552 | assert_eq!(x.to_index(dim, &conv((vec![(1, 2), (0, 1)], 1, (0, 2)))), 11usize.into()); 553 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 1)], 1, (1, 2)))), 12usize.into()); 554 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (0, 1)], 1, (1, 2)))), 13usize.into()); 555 | assert_eq!(x.to_index(dim, &conv((vec![(1, 2), (0, 1)], 1, (1, 2)))), 14usize.into()); 556 | assert_eq!(x.to_index(dim, &conv((vec![(0, 1), (0, 2)], 1, (1, 2)))), 15usize.into()); 557 | assert_eq!(x.to_index(dim, &conv((vec![(0, 2), (0, 2)], 1, (1, 2)))), 16usize.into()); 558 | assert_eq!(x.to_index(dim, &conv((vec![(1, 2), (0, 2)], 1, (1, 2)))), 17usize.into()); 559 | 560 | let mut pos = x.zero(dim); 561 | x.to_pos(dim, 16usize.into(), &mut pos); 562 | assert_eq!(pos, conv((vec![(0, 2), (0, 2)], 1, (1, 2)))); 563 | } 564 | } 565 | -------------------------------------------------------------------------------- /src/count.rs: -------------------------------------------------------------------------------- 1 | /// Implemented by spaces that can count the number of objects. 2 | pub trait Count { 3 | /// Counts the size of space given the dimensions. 4 | fn count(&self, dim: &T) -> N; 5 | } 6 | -------------------------------------------------------------------------------- /src/dimension.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use space::Space; 9 | 10 | /// Dimension is natural number, position is the same as index. 11 | pub struct Dimension(PhantomData); 12 | 13 | impl Construct for Dimension { 14 | fn new() -> Self { Dimension(PhantomData) } 15 | } 16 | 17 | impl Space for Dimension { 18 | type Dim = usize; 19 | type Pos = usize; 20 | 21 | fn count(&self, dim: &usize) -> usize { *dim } 22 | fn zero(&self, _dim: &usize) -> usize { 0 } 23 | fn to_index(&self, _dim: &usize, pos: &usize) -> usize { *pos } 24 | fn to_pos(&self, _dim: &usize, index: usize, pos: &mut usize) { 25 | *pos = index; 26 | } 27 | } 28 | 29 | impl Space for Dimension { 30 | type Dim = BigUint; 31 | type Pos = BigUint; 32 | 33 | fn count(&self, dim: &Self::Dim) -> BigUint { (*dim).clone() } 34 | fn zero(&self, _dim: &Self::Dim) -> BigUint { 0usize.into() } 35 | fn to_index(&self, _dim: &Self::Dim, pos: &Self::Pos) -> BigUint { (*pos).clone() } 36 | fn to_pos(&self, _dim: &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 37 | *pos = index; 38 | } 39 | } 40 | 41 | impl> Space for Dimension> { 42 | type Dim = T::Dim; 43 | type Pos = T::Pos; 44 | fn count(&self, dim: &Self::Dim) -> N { 45 | let of: T = Construct::new(); 46 | of.count(dim) 47 | } 48 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 49 | let of: T = Construct::new(); 50 | of.zero(dim) 51 | } 52 | fn to_index(&self, dim: &Self::Dim, pos: &Self::Pos) -> N { 53 | let of: T = Construct::new(); 54 | of.to_index(dim, pos) 55 | } 56 | fn to_pos(&self, dim: &Self::Dim, index: N, pos: &mut Self::Pos) { 57 | let of: T = Construct::new(); 58 | of.to_pos(dim, index, pos); 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | use super::super::*; 65 | 66 | #[test] 67 | fn features() { 68 | is_complete::(); 69 | is_complete::>>(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/dimension_n.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::ops::{ 3 | AddAssign, 4 | Div, 5 | Mul, 6 | MulAssign, 7 | SubAssign, 8 | DivAssign, 9 | }; 10 | 11 | use num::BigUint; 12 | 13 | use Construct; 14 | use Data; 15 | use Of; 16 | use space::Space; 17 | 18 | /// Dimension is a list of numbers, position is a list of numbers. 19 | pub struct DimensionN(PhantomData); 20 | 21 | impl Construct for DimensionN { 22 | fn new() -> Self { DimensionN(PhantomData) } 23 | } 24 | 25 | impl Space for DimensionN { 26 | type Dim = Vec; 27 | type Pos = Vec; 28 | fn count(&self, dim: &Vec) -> usize { 29 | let mut prod = 1; 30 | for i in 0..dim.len() { 31 | prod *= dim[i]; 32 | } 33 | prod 34 | } 35 | fn zero(&self, dim: &Vec) -> Vec { 36 | vec![0; dim.len()] 37 | } 38 | fn to_index(&self, dim: &Vec, pos: &Vec) -> usize { 39 | let mut dim_index = 0; 40 | for i in (0..dim.len()).rev() { 41 | dim_index = dim_index * dim[i] + pos[i]; 42 | } 43 | dim_index 44 | } 45 | fn to_pos(&self, dim: &Vec, index: usize, pos: &mut Vec) { 46 | unsafe { pos.set_len(0); } 47 | let mut prod: usize = self.count(dim); 48 | for _ in 0..dim.len() { 49 | pos.push(0); 50 | } 51 | let mut dim_index = index; 52 | for i in (0..dim.len()).rev() { 53 | prod /= dim[i]; 54 | let p_i = dim_index / prod; 55 | *pos.get_mut(i).unwrap() = p_i; 56 | dim_index -= p_i * prod; 57 | } 58 | } 59 | } 60 | 61 | impl Space for DimensionN { 62 | type Dim = Vec; 63 | type Pos = Vec; 64 | fn count(&self, dim: &Self::Dim) -> BigUint { 65 | let mut prod: BigUint = 1usize.into(); 66 | for i in 0..dim.len() { 67 | prod *= &dim[i]; 68 | } 69 | prod 70 | } 71 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 72 | vec![0usize.into(); dim.len()] 73 | } 74 | fn to_index(&self, dim: &Self::Dim, pos: &Self::Pos) -> BigUint { 75 | let mut dim_index: BigUint = 0usize.into(); 76 | for i in (0..dim.len()).rev() { 77 | dim_index = dim_index * &dim[i] + &pos[i]; 78 | } 79 | dim_index 80 | } 81 | fn to_pos(&self, dim: &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 82 | pos.clear(); 83 | let mut prod: BigUint = self.count(dim); 84 | for _ in 0..dim.len() { 85 | pos.push(0usize.into()); 86 | } 87 | let mut dim_index = index; 88 | for i in (0..dim.len()).rev() { 89 | prod /= &dim[i]; 90 | let p_i = &dim_index / ∏ 91 | dim_index -= &p_i * ∏ 92 | *pos.get_mut(i).unwrap() = p_i; 93 | } 94 | } 95 | } 96 | 97 | impl Space for DimensionN> 98 | where N: Clone + 99 | From + 100 | AddAssign + 101 | SubAssign + 102 | MulAssign + 103 | Div + 104 | DivAssign, 105 | for<'a> &'a N: Div<&'a N, Output = N> + Mul<&'a N, Output = N>, 106 | T: Space, 107 | { 108 | type Dim = Vec; 109 | type Pos = Vec; 110 | fn count(&self, dim: &Self::Dim) -> N { 111 | let of: T = Construct::new(); 112 | let mut prod: N = 1usize.into(); 113 | for i in 0..dim.len() { 114 | prod *= of.count(&dim[i]); 115 | } 116 | prod 117 | } 118 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 119 | let of: T = Construct::new(); 120 | let mut v = Vec::with_capacity(dim.len()); 121 | for i in 0..dim.len() { 122 | v.push(of.zero(&dim[i])); 123 | } 124 | v 125 | } 126 | fn to_index( 127 | &self, 128 | dim: &Self::Dim, 129 | pos: &Self::Pos, 130 | ) -> N { 131 | let of: T = Construct::new(); 132 | let mut dim_index: N = 0usize.into(); 133 | for i in (0..dim.len()).rev() { 134 | dim_index *= of.count(&dim[i]); 135 | dim_index += of.to_index(&dim[i], &pos[i]); 136 | } 137 | dim_index 138 | } 139 | fn to_pos( 140 | &self, 141 | dim: &Self::Dim, 142 | index: N, 143 | pos: &mut Self::Pos, 144 | ) { 145 | let of: T = Construct::new(); 146 | let mut prod = self.count(dim); 147 | let mut dim_index = index.clone(); 148 | for (i, p) in pos.iter_mut().enumerate().rev() { 149 | prod /= of.count(&dim[i]); 150 | let p_i = &dim_index / ∏ 151 | dim_index -= &p_i * ∏ 152 | of.to_pos(&dim[i], p_i, p); 153 | } 154 | } 155 | } 156 | 157 | #[cfg(test)] 158 | mod tests { 159 | use super::super::*; 160 | 161 | #[test] 162 | fn features() { 163 | is_complete::(); 164 | is_complete::>>(); 165 | } 166 | 167 | #[test] 168 | fn data() { 169 | let x: DimensionN = Construct::new(); 170 | let ref dim = vec![3, 3]; 171 | assert_eq!(x.count(dim), 9); 172 | assert_eq!(x.to_index(dim, &vec![0, 0]), 0); 173 | assert_eq!(x.to_index(dim, &vec![1, 0]), 1); 174 | assert_eq!(x.to_index(dim, &vec![0, 1]), 3); 175 | let mut new_pos = vec![0, 0]; 176 | x.to_pos(dim, 3, &mut new_pos); 177 | assert_eq!(&new_pos, &[0, 1]); 178 | } 179 | 180 | fn conv(v: Vec) -> Vec { 181 | v.into_iter().map(|n| n.into()).collect() 182 | } 183 | 184 | #[test] 185 | fn data_big() { 186 | let x: DimensionN = Construct::new(); 187 | let ref dim: Vec = conv(vec![3, 3]); 188 | assert_eq!(x.count(dim), 9usize.into()); 189 | assert_eq!(x.to_index(dim, &conv(vec![0, 0])), 0usize.into()); 190 | assert_eq!(x.to_index(dim, &conv(vec![1, 0])), 1usize.into()); 191 | assert_eq!(x.to_index(dim, &conv(vec![0, 1])), 3usize.into()); 192 | let mut new_pos = x.zero(dim); 193 | x.to_pos(dim, 3usize.into(), &mut new_pos); 194 | assert_eq!(new_pos, conv(vec![0, 1])); 195 | } 196 | 197 | #[test] 198 | fn of() { 199 | let x: DimensionN> = Construct::new(); 200 | let ref dim = vec![3, 4]; 201 | assert_eq!(x.count(dim), 18); 202 | assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 1)]), 0); 203 | assert_eq!(x.to_index(dim, &vec![(0, 2), (0, 1)]), 1); 204 | assert_eq!(x.to_index(dim, &vec![(1, 2), (0, 1)]), 2); 205 | assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3); 206 | let mut pos = vec![(0, 0), (0, 0)]; 207 | x.to_pos(dim, 3, &mut pos); 208 | assert_eq!(pos[0], (0, 1)); 209 | assert_eq!(pos[1], (0, 2)); 210 | } 211 | 212 | fn conv_pair(v: Vec<(usize, usize)>) -> Vec<(BigUint, BigUint)> { 213 | v.into_iter().map(|(a, b)| (a.into(), b.into())).collect() 214 | } 215 | 216 | #[test] 217 | fn of_big() { 218 | let x: DimensionN> = Construct::new(); 219 | let ref dim = conv(vec![3, 4]); 220 | assert_eq!(x.count(dim), 18usize.into()); 221 | assert_eq!(x.to_index(dim, &conv_pair(vec![(0, 1), (0, 1)])), 0usize.into()); 222 | assert_eq!(x.to_index(dim, &conv_pair(vec![(0, 2), (0, 1)])), 1usize.into()); 223 | assert_eq!(x.to_index(dim, &conv_pair(vec![(1, 2), (0, 1)])), 2usize.into()); 224 | assert_eq!(x.to_index(dim, &conv_pair(vec![(0, 1), (0, 2)])), 3usize.into()); 225 | let mut pos = x.zero(dim); 226 | x.to_pos(dim, 3usize.into(), &mut pos); 227 | assert_eq!(pos, conv_pair(vec![(0, 1), (0, 2)])); 228 | } 229 | 230 | #[test] 231 | fn zero() { 232 | let x: DimensionN = Construct::new(); 233 | let ref dim = vec![2; 3]; 234 | assert_eq!(x.zero(dim), vec![0; 3]); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/directed_context.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::marker::PhantomData; 3 | use std::ops::{ 4 | Add, 5 | Mul, 6 | MulAssign, 7 | Sub, 8 | Div, 9 | Rem, 10 | AddAssign, 11 | DivAssign, 12 | SubAssign, 13 | }; 14 | 15 | use num::BigUint; 16 | 17 | use Construct; 18 | use Data; 19 | use Of; 20 | use NeqPair; 21 | use Pair; 22 | use space::Space; 23 | 24 | /// Same as `Context`, but for directed edges. 25 | pub struct DirectedContext(PhantomData); 26 | 27 | impl Construct for DirectedContext { 28 | fn new() -> Self { DirectedContext(PhantomData) } 29 | } 30 | 31 | impl Space for DirectedContext { 32 | type Dim = Vec; 33 | type Pos = (Vec, usize, usize); 34 | fn count(&self, dim: &Vec) -> usize { 35 | let pair: NeqPair = Construct::new(); 36 | let mut sum: usize = pair.count(&dim[0]); 37 | let mut prod = dim[0]; 38 | for d in &dim[1..] { 39 | let count: usize = pair.count(d); 40 | sum = d * sum + count * prod; 41 | prod *= *d; 42 | } 43 | sum 44 | } 45 | fn zero(&self, dim: &Vec) -> (Vec, usize, usize) { 46 | (vec![0; dim.len()], 0, 0) 47 | } 48 | fn to_index( 49 | &self, dim: &Vec, 50 | &(ref p, ind, b): &(Vec, usize, usize) 51 | ) -> usize { 52 | use Context; 53 | 54 | let context: Context = Construct::new(); 55 | let index: usize = context.to_index(dim, &(p.clone(), ind, b)); 56 | if p[ind] > b { 57 | 2 * index + 1 58 | } else { 59 | 2 * index 60 | } 61 | } 62 | fn to_pos( 63 | &self, 64 | dim: &Vec, 65 | index: usize, 66 | pos: &mut (Vec, usize, usize) 67 | ) { 68 | use Context; 69 | 70 | let context: Context = Construct::new(); 71 | if index % 2 == 0 { 72 | context.to_pos(dim, index / 2, pos); 73 | } else { 74 | context.to_pos(dim, (index - 1) / 2, pos); 75 | let tmp = pos.0[pos.1]; 76 | pos.0[pos.1] = pos.2; 77 | pos.2 = tmp; 78 | } 79 | } 80 | } 81 | 82 | impl Space for DirectedContext { 83 | type Dim = Vec; 84 | type Pos = (Vec, usize, BigUint); 85 | fn count(&self, dim: &Vec) -> BigUint { 86 | let pair: NeqPair = Construct::new(); 87 | let mut sum: BigUint = pair.count(&dim[0]); 88 | let mut prod = dim[0].clone(); 89 | for d in &dim[1..] { 90 | let count: BigUint = pair.count(d); 91 | sum = d * sum + count * ∏ 92 | prod *= d; 93 | } 94 | sum 95 | } 96 | fn zero(&self, dim: &Vec) -> (Vec, usize, BigUint) { 97 | (vec![0usize.into(); dim.len()], 0, 0usize.into()) 98 | } 99 | fn to_index( 100 | &self, dim: &Self::Dim, 101 | (p, ind, b): &Self::Pos, 102 | ) -> BigUint { 103 | use Context; 104 | 105 | let context: Context = Construct::new(); 106 | let index: BigUint = context.to_index(dim, &(p.clone(), *ind, b.clone())); 107 | if &p[*ind] > b { 108 | 2usize * index + 1usize 109 | } else { 110 | 2usize * index 111 | } 112 | } 113 | fn to_pos( 114 | &self, 115 | dim: &Self::Dim, 116 | index: BigUint, 117 | pos: &mut Self::Pos, 118 | ) { 119 | use Context; 120 | 121 | let context: Context = Construct::new(); 122 | if &index % 2usize == 0usize.into() { 123 | context.to_pos(dim, index / 2usize, pos); 124 | } else { 125 | context.to_pos(dim, (index - 1usize) / 2usize, pos); 126 | std::mem::swap(&mut pos.0[pos.1], &mut pos.2); 127 | } 128 | } 129 | } 130 | 131 | impl Space for DirectedContext> 132 | where T: Space, 133 | T::Pos: Clone, 134 | NeqPair: Space, 135 | Pair: Space, 136 | for<'a> N: Clone + 137 | From + 138 | Ord + 139 | MulAssign<&'a N> + 140 | Sub + 141 | Div + 142 | AddAssign<&'a N> + 143 | DivAssign<&'a N> + 144 | SubAssign<&'a N> + 145 | Mul + 146 | Add, 147 | for<'a> &'a N: Mul<&'a N, Output = N> + 148 | Add<&'a N, Output = N> + 149 | Rem + 150 | Sub<&'a N, Output = N> + 151 | Div<&'a N, Output = N>, 152 | { 153 | type Dim = Vec; 154 | type Pos = (Vec, usize, T::Pos); 155 | fn count(&self, dim: &Self::Dim) -> N { 156 | let of: T = Construct::new(); 157 | let pair: NeqPair = Construct::new(); 158 | let mut sum: N = pair.count(&of.count(&dim[0])); 159 | let mut prod: N = of.count(&dim[0]); 160 | for d in &dim[1..] { 161 | let d = of.count(d); 162 | let count: N = pair.count(&d); 163 | sum = &(&d * &sum) + &(&count * &prod); 164 | prod *= &d; 165 | } 166 | sum 167 | } 168 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 169 | let of: T = Construct::new(); 170 | let mut v = Vec::with_capacity(dim.len()); 171 | for i in 0..dim.len() { 172 | v.push(of.zero(&dim[i])); 173 | } 174 | (v, 0, of.zero(&dim[0])) 175 | } 176 | fn to_index( 177 | &self, 178 | dim: &Self::Dim, 179 | &(ref p, ind, ref b): &Self::Pos, 180 | ) -> N { 181 | use Context; 182 | 183 | let of: T = Construct::new(); 184 | let context: Context> = Construct::new(); 185 | let index: N = Space::to_index(&context, dim, &(p.clone(), ind, b.clone())); 186 | if of.to_index(&dim[ind], &p[ind]) > of.to_index(&dim[ind], b) { 187 | let x = index * 2usize; 188 | x + 1usize 189 | } else { 190 | index * 2usize 191 | } 192 | } 193 | fn to_pos( 194 | &self, 195 | dim: &Self::Dim, 196 | index: N, 197 | pos: &mut Self::Pos, 198 | ) { 199 | use Context; 200 | 201 | let context: Context> = Construct::new(); 202 | if &index % 2usize == 0usize.into() { 203 | context.to_pos(dim, index / 2usize, pos); 204 | } else { 205 | context.to_pos(dim, (index - 1usize) / 2usize, pos); 206 | std::mem::swap(&mut pos.0[pos.1], &mut pos.2); 207 | } 208 | } 209 | } 210 | 211 | #[cfg(test)] 212 | mod tests { 213 | use super::super::*; 214 | 215 | #[test] 216 | fn features() { 217 | is_complete::(); 218 | is_complete::>>(); 219 | } 220 | 221 | #[test] 222 | fn data() { 223 | let x: DirectedContext = Construct::new(); 224 | let ref dim = vec![2, 2, 2]; 225 | // 12 edges on a cube * 2 = 24 directed edges 226 | assert_eq!(x.count(dim), 24); 227 | assert_eq!(x.to_index(dim, &(vec![0, 0, 0], 0, 1)), 0); 228 | assert_eq!(x.to_index(dim, &(vec![1, 0, 0], 0, 0)), 1); 229 | for i in 0..x.count(dim) { 230 | let mut pos = (vec![], 0, 0); 231 | x.to_pos(dim, i, &mut pos); 232 | // println!("{:?}", pos); 233 | assert_eq!(x.to_index(dim, &pos), i); 234 | } 235 | // assert!(false); 236 | } 237 | 238 | fn conv(v: Vec) -> Vec { 239 | v.into_iter().map(|n| n.into()).collect() 240 | } 241 | 242 | fn conv_pos((v, a, b): (Vec, usize, usize)) -> (Vec, usize, BigUint) { 243 | (conv(v), a, b.into()) 244 | } 245 | 246 | #[test] 247 | fn data_big() { 248 | use std::convert::TryInto; 249 | 250 | let x: DirectedContext = Construct::new(); 251 | let ref dim = conv(vec![2, 2, 2]); 252 | // 12 edges on a cube * 2 = 24 directed edges 253 | assert_eq!(x.count(dim), 24usize.into()); 254 | assert_eq!(x.to_index(dim, &conv_pos((vec![0, 0, 0], 0, 1))), 0usize.into()); 255 | assert_eq!(x.to_index(dim, &conv_pos((vec![1, 0, 0], 0, 0))), 1usize.into()); 256 | let count: usize = x.count(dim).try_into().unwrap(); 257 | for i in 0usize..count { 258 | let mut pos = x.zero(dim); 259 | x.to_pos(dim, i.into(), &mut pos); 260 | // println!("{:?}", pos); 261 | assert_eq!(x.to_index(dim, &pos), i.into()); 262 | } 263 | // assert!(false); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/either.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use std::ops::{Add, Sub}; 4 | 5 | use Construct; 6 | use space::Space; 7 | 8 | /// Selects between two spaces. 9 | pub struct Either(PhantomData, PhantomData); 10 | 11 | /// Selects between spaces. 12 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 13 | pub enum Select { 14 | /// The first space. 15 | Fst(T), 16 | /// The second space. 17 | Snd(U), 18 | } 19 | 20 | impl Construct for Either { 21 | fn new() -> Self { Either(PhantomData, PhantomData) } 22 | } 23 | 24 | impl Space for Either 25 | where T: Space, 26 | U: Space, 27 | N: Add + 28 | Sub + 29 | PartialOrd, 30 | { 31 | type Dim = (T::Dim, U::Dim); 32 | type Pos = Select; 33 | fn count(&self, &(ref dim_t, ref dim_u): &Self::Dim) -> N { 34 | let t: T = Construct::new(); 35 | let u: U = Construct::new(); 36 | t.count(dim_t) + u.count(dim_u) 37 | } 38 | fn zero(&self, &(ref dim_t, _): &Self::Dim) -> Self::Pos { 39 | let t: T = Construct::new(); 40 | Select::Fst(t.zero(dim_t)) 41 | } 42 | fn to_index( 43 | &self, 44 | &(ref dim_t, ref dim_u): &Self::Dim, 45 | s: &Self::Pos 46 | ) -> N { 47 | let t: T = Construct::new(); 48 | let u: U = Construct::new(); 49 | match *s { 50 | Select::Fst(ref pt) => { 51 | t.to_index(dim_t, pt) 52 | } 53 | Select::Snd(ref pu) => { 54 | let count = t.count(dim_t); 55 | count + u.to_index(dim_u, pu) 56 | } 57 | } 58 | } 59 | fn to_pos( 60 | &self, 61 | &(ref dim_t, ref dim_u): &Self::Dim, 62 | ind: N, 63 | pos: &mut Self::Pos, 64 | ) { 65 | let t: T = Construct::new(); 66 | let u: U = Construct::new(); 67 | let count = t.count(dim_t); 68 | if ind < count { 69 | let mut zero = t.zero(dim_t); 70 | t.to_pos(dim_t, ind, &mut zero); 71 | *pos = Select::Fst(zero) 72 | } else { 73 | let mut zero = u.zero(dim_u); 74 | u.to_pos(dim_u, ind - count, &mut zero); 75 | *pos = Select::Snd(zero) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/eq_pair.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use space::Space; 9 | 10 | /// Dimension is natural number, position is (min, max). 11 | pub struct EqPair(PhantomData); 12 | 13 | impl Construct for EqPair { 14 | fn new() -> Self { EqPair(PhantomData) } 15 | } 16 | 17 | impl Space for EqPair { 18 | type Dim = usize; 19 | type Pos = (usize, usize); 20 | fn count(&self, dim: &usize) -> usize { dim * (dim + 1) / 2 } 21 | fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) } 22 | fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize { 23 | min + max * (max + 1) / 2 24 | } 25 | fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) { 26 | let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize; 27 | let min = index - max * (max + 1) / 2; 28 | *pos = (min, max) 29 | } 30 | } 31 | 32 | impl Space for EqPair { 33 | type Dim = BigUint; 34 | type Pos = (BigUint, BigUint); 35 | fn count(&self, dim: &Self::Dim) -> BigUint { dim * (dim + 1usize) / 2usize } 36 | fn zero(&self, _dim: &Self::Dim) -> Self::Pos { (0usize.into(), 0usize.into()) } 37 | fn to_index(&self, _dim: &Self::Dim, (min, max): &Self::Pos) -> BigUint { 38 | min + max * (max + 1usize) / 2usize 39 | } 40 | fn to_pos(&self, _dim: &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 41 | let max: BigUint = ((8usize * &index + 1usize).sqrt() - 1usize) / 2usize; 42 | let min: BigUint = index - &max * (&max + 1usize) / 2usize; 43 | *pos = (min, max) 44 | } 45 | } 46 | 47 | impl Space for EqPair> 48 | where T: Space, 49 | EqPair: Space, 50 | { 51 | type Dim = T::Dim; 52 | type Pos = (T::Pos, T::Pos); 53 | fn count(&self, dim: &Self::Dim) -> N { 54 | let of: T = Construct::new(); 55 | let data: EqPair = Construct::new(); 56 | data.count(&of.count(dim)) 57 | } 58 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 59 | let of: T = Construct::new(); 60 | (of.zero(dim), of.zero(dim)) 61 | } 62 | fn to_index( 63 | &self, 64 | dim: &Self::Dim, 65 | &(ref min, ref max): &Self::Pos, 66 | ) -> N { 67 | let of: T = Construct::new(); 68 | let data: EqPair = Construct::new(); 69 | let min = of.to_index(dim, min); 70 | let max = of.to_index(dim, max); 71 | data.to_index(&self.count(dim), &(min, max)) 72 | } 73 | fn to_pos( 74 | &self, 75 | dim: &Self::Dim, 76 | index: N, 77 | &mut (ref mut min, ref mut max): &mut Self::Pos, 78 | ) { 79 | let of: T = Construct::new(); 80 | let data: EqPair = Construct::new(); 81 | let count = of.count(dim); 82 | let mut pair = data.zero(&count); 83 | data.to_pos(&count, index, &mut pair); 84 | let (pair_min, pair_max) = pair; 85 | of.to_pos(dim, pair_min, min); 86 | of.to_pos(dim, pair_max, max); 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod tests { 92 | use super::super::*; 93 | 94 | #[test] 95 | fn features() { 96 | is_complete::(); 97 | is_complete::>>(); 98 | } 99 | 100 | #[test] 101 | fn test_eq_pair() { 102 | // 1 0 0 0 103 | // 2 3 0 0 104 | // 4 5 6 0 105 | // 7 8 9 10 106 | 107 | let eq_pair: EqPair = Construct::new(); 108 | let ref n = 4; 109 | let count = eq_pair.count(n); 110 | assert_eq!(count, 10); 111 | 112 | let mut pos = (0, 0); 113 | for x in 0..count { 114 | eq_pair.to_pos(n, x, &mut pos); 115 | println!("{:?}", pos); 116 | assert_eq!(eq_pair.to_index(n, &pos), x); 117 | } 118 | } 119 | 120 | #[test] 121 | fn test_eq_pair_big() { 122 | use std::convert::TryInto; 123 | 124 | // 1 0 0 0 125 | // 2 3 0 0 126 | // 4 5 6 0 127 | // 7 8 9 10 128 | 129 | let eq_pair: EqPair = Construct::new(); 130 | let ref n: BigUint = 4usize.into(); 131 | let count = eq_pair.count(n); 132 | assert_eq!(count, 10usize.into()); 133 | 134 | let mut pos = eq_pair.zero(n); 135 | let count: usize = count.try_into().unwrap(); 136 | for x in 0..count { 137 | eq_pair.to_pos(n, x.into(), &mut pos); 138 | println!("{:?}", pos); 139 | assert_eq!(eq_pair.to_index(n, &pos), x.into()); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/homotopy.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use EqPair; 9 | use space::Space; 10 | 11 | /// Stores a higher order point for homotopy spaces. 12 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 13 | pub enum HPoint { 14 | /// A point. 15 | Point(T), 16 | /// A path between two higher order points. 17 | Path(Box<(HPoint, HPoint)>), 18 | } 19 | 20 | impl HPoint { 21 | /// Gets the homotopy level of a higher order point for homotopy spaces. 22 | pub fn level(&self) -> usize { 23 | use HPoint::*; 24 | 25 | match self { 26 | Point(_) => 0, 27 | Path(ab) => ab.0.level().max(ab.1.level()) + 1, 28 | } 29 | } 30 | } 31 | 32 | /// A discrete space that models undirected homotopy paths 33 | /// at a specified homotopy level. 34 | /// 35 | /// A homotopy level is a space that connects pieces of 36 | /// lower homotopy levels. 37 | /// Homotopy level 0 consists of the space of the pieces themselves. 38 | /// 39 | /// Dimension is `(, )`, 40 | /// position is `HPoint`. 41 | /// 42 | /// Uses `EqPair` internally to include loop spaces. 43 | pub struct Homotopy(PhantomData); 44 | 45 | impl Construct for Homotopy { 46 | fn new() -> Self {Homotopy(PhantomData)} 47 | } 48 | 49 | impl Space for Homotopy { 50 | type Dim = (usize, usize); 51 | type Pos = HPoint; 52 | fn count(&self, &(level, n): &(usize, usize)) -> usize { 53 | let s: EqPair = Construct::new(); 54 | let mut count = n; 55 | for _ in 0..level { 56 | count = s.count(&count); 57 | } 58 | count 59 | } 60 | fn zero(&self, &(level, n): &(usize, usize)) -> HPoint { 61 | use HPoint::*; 62 | 63 | match level { 64 | 0 => Point(0), 65 | _ => Path(Box::new(( 66 | Space::::zero(self, &(level-1, n)), 67 | Space::::zero(self, &(level-1, n))))), 68 | } 69 | } 70 | fn to_index(&self, &(level, n): &(usize, usize), pos: &HPoint) -> usize { 71 | use HPoint::*; 72 | 73 | match pos { 74 | Point(x) => *x, 75 | Path(ab) => { 76 | let count = self.count(&(level, n)); 77 | let a: usize = self.to_index(&(level-1, n), &ab.0); 78 | let b: usize = self.to_index(&(level-1, n), &ab.1); 79 | let min = a.min(b); 80 | let max = a.max(b); 81 | let s: EqPair = Construct::new(); 82 | s.to_index(&count, &(min, max)) 83 | } 84 | } 85 | } 86 | fn to_pos(&self, &(level, n): &(usize, usize), index: usize, pos: &mut HPoint) { 87 | use HPoint::*; 88 | 89 | match level { 90 | 0 => { 91 | *pos = Point(index); 92 | return; 93 | } 94 | 1 => { 95 | let s: EqPair = Construct::new(); 96 | let mut ab = (0, 0); 97 | s.to_pos(&n, index, &mut ab); 98 | *pos = Path(Box::new((Point(ab.0), Point(ab.1)))); 99 | return; 100 | } 101 | _ => { 102 | let count = self.count(&(level, n)); 103 | let s: EqPair = Construct::new(); 104 | let mut ab = (0, 0); 105 | s.to_pos(&count, index, &mut ab); 106 | let mut a = Point(0); 107 | let mut b = Point(0); 108 | self.to_pos(&(level - 1, n), ab.0, &mut a); 109 | self.to_pos(&(level - 1, n), ab.1, &mut b); 110 | *pos = Path(Box::new((a, b))); 111 | return; 112 | } 113 | } 114 | } 115 | } 116 | 117 | impl Space for Homotopy { 118 | type Dim = (usize, BigUint); 119 | type Pos = HPoint; 120 | fn count(&self, (level, n): &Self::Dim) -> BigUint { 121 | let s: EqPair = Construct::new(); 122 | let mut count = n.clone(); 123 | for _ in 0..*level { 124 | count = s.count(&count); 125 | } 126 | count 127 | } 128 | fn zero(&self, (level, n): &Self::Dim) -> Self::Pos { 129 | use HPoint::*; 130 | 131 | match *level { 132 | 0 => Point(0usize.into()), 133 | _ => Path(Box::new(( 134 | Space::::zero(self, &(level-1, n.clone())), 135 | Space::::zero(self, &(level-1, n.clone())) 136 | ))), 137 | } 138 | } 139 | fn to_index(&self, (level, n): &Self::Dim, pos: &Self::Pos) -> BigUint { 140 | use HPoint::*; 141 | 142 | let level = *level; 143 | match pos { 144 | Point(x) => x.clone(), 145 | Path(ab) => { 146 | let count = self.count(&(level, n.clone())); 147 | let a: BigUint = self.to_index(&(level-1, n.clone()), &ab.0); 148 | let b: BigUint = self.to_index(&(level-1, n.clone()), &ab.1); 149 | let min = a.clone().min(b.clone()); 150 | let max = a.max(b); 151 | let s: EqPair = Construct::new(); 152 | s.to_index(&count, &(min, max)) 153 | } 154 | } 155 | } 156 | fn to_pos(&self, (level, n): &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 157 | use HPoint::*; 158 | 159 | let level = *level; 160 | match level { 161 | 0 => { 162 | *pos = Point(index); 163 | return; 164 | } 165 | 1 => { 166 | let s: EqPair = Construct::new(); 167 | let mut ab = (0usize.into(), 0usize.into()); 168 | s.to_pos(n, index, &mut ab); 169 | *pos = Path(Box::new((Point(ab.0), Point(ab.1)))); 170 | return; 171 | } 172 | _ => { 173 | let count: BigUint = self.count(&(level, n.clone())); 174 | let s: EqPair = Construct::new(); 175 | let mut ab = (0usize.into(), 0usize.into()); 176 | s.to_pos(&count, index, &mut ab); 177 | let mut a: HPoint = Point(0usize.into()); 178 | let mut b: HPoint = Point(0usize.into()); 179 | self.to_pos(&(level - 1, n.clone()), ab.0, &mut a); 180 | self.to_pos(&(level - 1, n.clone()), ab.1, &mut b); 181 | *pos = Path(Box::new((a, b))); 182 | return; 183 | } 184 | } 185 | } 186 | } 187 | 188 | impl Space for Homotopy> 189 | where T: Space, 190 | T::Dim: Clone, 191 | EqPair: Space, 192 | EqPair>: Space, 193 | N: Clone + 194 | Ord + 195 | From, 196 | Homotopy: Space>, 197 | { 198 | type Dim = (usize, T::Dim); 199 | type Pos = HPoint; 200 | fn count(&self, (level, dim): &Self::Dim) -> N { 201 | let of: T = Construct::new(); 202 | let data: Homotopy = Construct::new(); 203 | data.count(&(*level, of.count(dim))) 204 | } 205 | fn zero(&self, (level, dim): &Self::Dim) -> Self::Pos { 206 | use HPoint::*; 207 | 208 | match level { 209 | 0 => { 210 | let of: T = Construct::new(); 211 | Point(of.zero(&dim)) 212 | } 213 | _ => Path(Box::new((self.zero(&(level-1, dim.clone())), 214 | self.zero(&(level-1, dim.clone()))))), 215 | } 216 | } 217 | fn to_index( 218 | &self, 219 | dim: &Self::Dim, 220 | pos: &Self::Pos, 221 | ) -> N { 222 | use HPoint::*; 223 | 224 | match pos { 225 | Point(x) => { 226 | let of: T = Construct::new(); 227 | of.to_index(&dim.1, x) 228 | } 229 | Path(ab) => { 230 | let count = self.count(dim); 231 | let dim_n = (dim.0-1, dim.1.clone()); 232 | let a = self.to_index(&dim_n, &ab.0); 233 | let b = self.to_index(&dim_n, &ab.1); 234 | let min = a.clone().min(b.clone()); 235 | let max = a.max(b); 236 | let s: EqPair = Construct::new(); 237 | s.to_index(&count, &(min, max)) 238 | } 239 | } 240 | } 241 | fn to_pos( 242 | &self, 243 | &(level, ref dim): &Self::Dim, 244 | index: N, 245 | pos: &mut Self::Pos, 246 | ) { 247 | use HPoint::*; 248 | 249 | match level { 250 | 0 => { 251 | let of: T = Construct::new(); 252 | let mut of_pos = of.zero(dim); 253 | of.to_pos(dim, index, &mut of_pos); 254 | *pos = Point(of_pos); 255 | return; 256 | } 257 | 1 => { 258 | let of: T = Construct::new(); 259 | let s: EqPair> = Construct::new(); 260 | let mut ab = (of.zero(dim), of.zero(dim)); 261 | s.to_pos(&dim, index, &mut ab); 262 | *pos = Path(Box::new((Point(ab.0), Point(ab.1)))); 263 | return; 264 | } 265 | _ => { 266 | let of: T = Construct::new(); 267 | let count = self.count(&(level, dim.clone())); 268 | let s: EqPair = Construct::new(); 269 | let mut ab = (0usize.into(), 0usize.into()); 270 | s.to_pos(&count, index, &mut ab); 271 | let mut a: HPoint = Point(of.zero(dim)); 272 | let mut b: HPoint = Point(of.zero(dim)); 273 | self.to_pos(&(level - 1, dim.clone()), ab.0, &mut a); 274 | self.to_pos(&(level - 1, dim.clone()), ab.1, &mut b); 275 | *pos = Path(Box::new((a, b))); 276 | return; 277 | } 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | 3 | //! Combinatorial phantom types for discrete mathematics. 4 | //! 5 | //! All discrete spaces have the following functions: 6 | //! 7 | //! ~~~ignore 8 | //! fn count(dim) -> usize; 9 | //! fn to_index(dim, pos) -> usize; 10 | //! fn to_pos(dim, index, &mut pos); 11 | //! ~~~ 12 | //! 13 | //! A discrete space is countable and has a one-to-one map 14 | //! with the natural numbers. 15 | //! 16 | //! For example, a pair of natural numbers is a discrete space. 17 | //! There exists an algorithm that converts each pair of numbers 18 | //! into a number. Likewise there exists an algorithm that 19 | //! takes a number and converts it into a pair. 20 | //! 21 | //! To construct a pair, you write: 22 | //! 23 | //! ~~~ignore 24 | //! let x: Pair = Construct::new(); 25 | //! ~~~ 26 | //! 27 | //! The `x` above is a phantom variable, which means it does not use memory 28 | //! in the compiled program. The phantom variable represents the discrete space 29 | //! that we have constructed. Now we can call methods on the space 30 | //! to examine its discrete structure. 31 | //! 32 | //! A pair can be visualized as edges between points. 33 | //! If we have 4 points then we can create 6 edges: 34 | //! 35 | //! ```text 36 | //! o---o 37 | //! |\ /| 38 | //! | X | 39 | //! |/ \| 40 | //! o---o 41 | //! ``` 42 | //! 43 | //! To check this we can write: 44 | //! 45 | //! ~~~ignore 46 | //! let dim = 4; // number of points 47 | //! assert_eq!(x.count(dim), 6); // count edges 48 | //! ~~~ 49 | //! 50 | //! Phantom types makes it possible to construct advanced discrete spaces. 51 | //! By using a generic program, the algorithms to examine the structure 52 | //! follows from the construction of the space. 53 | //! 54 | //! This makes it possible to solve tasks such as: 55 | //! 56 | //! - Compute upper bounds for many problems 57 | //! - Store data with a non-trivial structure 58 | //! - Convert from and to natural numbers 59 | //! - Iterate through all elements of a space 60 | //! - Pick a random object of the space 61 | //! 62 | //! Iterating through all elements of a space can be done simply 63 | //! by counting from zero up to the size of the space. 64 | //! For each number, we convert to a position within the space. 65 | //! 66 | //! Picking a random object of the space can be done by generating 67 | //! a random number between 0 and the size of the space. 68 | //! 69 | //! ### Advanced spaces 70 | //! 71 | //! Phantom types are used because they represent the general spaces. 72 | //! For example, we can represent a general two-dimensional space, 73 | //! instead of binding the type to the size. 74 | //! 75 | //! For any constructed space, there is a dimension and position type. 76 | //! The dimension and position types are compositions, 77 | //! given by the type of the constructed space. 78 | 79 | extern crate num; 80 | 81 | use std::marker::PhantomData; 82 | 83 | pub use construct::Construct; 84 | pub use count::Count; 85 | pub use zero::Zero; 86 | pub use to_index::ToIndex; 87 | pub use to_pos::ToPos; 88 | 89 | pub use power_set::PowerSet; 90 | pub use dimension_n::DimensionN; 91 | pub use dimension::Dimension; 92 | pub use pair::Pair; 93 | pub use eq_pair::EqPair; 94 | pub use neq_pair::NeqPair; 95 | pub use sq_pair::SqPair; 96 | pub use permutation::Permutation; 97 | pub use context::Context; 98 | pub use directed_context::DirectedContext; 99 | pub use either::{Either, Select}; 100 | pub use homotopy::{Homotopy, HPoint}; 101 | pub use num::BigUint; 102 | 103 | pub mod space; 104 | 105 | mod construct; 106 | mod count; 107 | mod zero; 108 | mod to_index; 109 | mod to_pos; 110 | 111 | mod power_set; 112 | mod dimension_n; 113 | mod dimension; 114 | mod pair; 115 | mod eq_pair; 116 | mod neq_pair; 117 | mod sq_pair; 118 | mod permutation; 119 | mod context; 120 | mod directed_context; 121 | mod subspace; 122 | mod either; 123 | mod homotopy; 124 | 125 | /// Used by the final subspace. 126 | #[derive(Copy, Clone)] 127 | pub struct Data; 128 | /// Used to combine the dimensional and position types. 129 | pub struct Of(PhantomData); 130 | 131 | // N - numeric type 132 | // T - discrete space 133 | #[cfg(test)] 134 | pub fn is_complete() 135 | where 136 | T: space::Space 137 | {} 138 | -------------------------------------------------------------------------------- /src/neq_pair.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use space::Space; 9 | 10 | /// Dimension is natural number, position is (a, b). 11 | /// Represents all directional pairs that has not same element for `a` and `b`. 12 | pub struct NeqPair(PhantomData); 13 | 14 | impl Construct for NeqPair { 15 | fn new() -> Self { NeqPair(PhantomData) } 16 | } 17 | 18 | impl Space for NeqPair { 19 | type Dim = usize; 20 | type Pos = (usize, usize); 21 | fn count(&self, dim: &usize) -> usize { dim * (dim - 1) } 22 | fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) } 23 | fn to_index(&self, dim: &usize, &(a, b): &(usize, usize)) -> usize { 24 | use Pair; 25 | 26 | let pair: Pair = Construct::new(); 27 | if a < b { 28 | >::to_index(&pair, dim, &(a, b)) * 2 29 | } else { 30 | >::to_index(&pair, dim, &(b, a)) * 2 + 1 31 | } 32 | } 33 | fn to_pos(&self, dim: &usize, index: usize, pos: &mut (usize, usize)) { 34 | use Pair; 35 | 36 | let pair: Pair = Construct::new(); 37 | if index % 2 == 0 { 38 | pair.to_pos(dim, index / 2, pos); 39 | } else { 40 | pair.to_pos(dim, (index - 1) / 2, pos); 41 | let tmp = pos.1; 42 | pos.1 = pos.0; 43 | pos.0 = tmp; 44 | } 45 | } 46 | } 47 | 48 | impl Space for NeqPair { 49 | type Dim = BigUint; 50 | type Pos = (BigUint, BigUint); 51 | fn count(&self, dim: &BigUint) -> BigUint { 52 | dim * (dim - 1usize) 53 | } 54 | fn zero(&self, _dim: &BigUint) -> (BigUint, BigUint) { (0usize.into(), 0usize.into()) } 55 | fn to_index(&self, dim: &Self::Dim, (a, b): &Self::Pos) -> BigUint { 56 | use Pair; 57 | 58 | let pair: Pair = Construct::new(); 59 | if a < b { 60 | >::to_index(&pair, dim, &(a.clone(), b.clone())) * 2usize 61 | } else { 62 | >::to_index(&pair, dim, &(b.clone(), a.clone())) * 2usize + 1usize 63 | } 64 | } 65 | fn to_pos(&self, dim: &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 66 | use Pair; 67 | 68 | let pair: Pair = Construct::new(); 69 | if &index % 2usize == 0usize.into() { 70 | pair.to_pos(dim, index / 2usize, pos); 71 | } else { 72 | pair.to_pos(dim, (index - 1usize) / 2usize, pos); 73 | std::mem::swap(&mut pos.0, &mut pos.1); 74 | } 75 | } 76 | } 77 | 78 | impl Space for NeqPair> 79 | where T: Space, 80 | NeqPair: Space, 81 | { 82 | type Dim = T::Dim; 83 | type Pos = (T::Pos, T::Pos); 84 | fn count(&self, dim: &Self::Dim) -> N { 85 | let of: T = Construct::new(); 86 | let data: NeqPair = Construct::new(); 87 | data.count(&of.count(dim)) 88 | } 89 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 90 | let of: T = Construct::new(); 91 | (of.zero(dim), of.zero(dim)) 92 | } 93 | fn to_index( 94 | &self, 95 | dim: &Self::Dim, 96 | &(ref min, ref max): &Self::Pos, 97 | ) -> N { 98 | let of: T = Construct::new(); 99 | let data: NeqPair = Construct::new(); 100 | let min = of.to_index(dim, min); 101 | let max = of.to_index(dim, max); 102 | data.to_index(&self.count(dim), &(min, max)) 103 | } 104 | fn to_pos( 105 | &self, 106 | dim: &Self::Dim, 107 | index: N, 108 | &mut (ref mut min, ref mut max): &mut Self::Pos, 109 | ) { 110 | let of: T = Construct::new(); 111 | let data: NeqPair = Construct::new(); 112 | let count = of.count(dim); 113 | let mut pair = data.zero(&count); 114 | data.to_pos(&count, index, &mut pair); 115 | let (pair_min, pair_max) = pair; 116 | of.to_pos(dim, pair_min, min); 117 | of.to_pos(dim, pair_max, max); 118 | } 119 | } 120 | 121 | #[cfg(test)] 122 | mod tests { 123 | use super::super::*; 124 | 125 | #[test] 126 | fn features() { 127 | is_complete::(); 128 | is_complete::>>(); 129 | } 130 | 131 | #[test] 132 | fn data() { 133 | let x: NeqPair = Construct::new(); 134 | let ref dim = 4; 135 | assert_eq!(x.count(dim), 12); 136 | assert_eq!(x.to_index(dim, &(0, 1)), 0); 137 | assert_eq!(x.to_index(dim, &(1, 0)), 1); 138 | assert_eq!(x.to_index(dim, &(0, 2)), 2); 139 | assert_eq!(x.to_index(dim, &(2, 0)), 3); 140 | assert_eq!(x.to_index(dim, &(1, 2)), 4); 141 | assert_eq!(x.to_index(dim, &(2, 1)), 5); 142 | assert_eq!(x.to_index(dim, &(0, 3)), 6); 143 | let mut new_pos = (0, 0); 144 | x.to_pos(dim, 6, &mut new_pos); 145 | assert_eq!(new_pos, (0, 3)); 146 | x.to_pos(dim, 5, &mut new_pos); 147 | assert_eq!(new_pos, (2, 1)); 148 | } 149 | 150 | fn conv_pos((a, b): (usize, usize)) -> (BigUint, BigUint) { 151 | (a.into(), b.into()) 152 | } 153 | 154 | #[test] 155 | fn data_big() { 156 | let x: NeqPair = Construct::new(); 157 | let ref dim: BigUint = 4usize.into(); 158 | assert_eq!(x.count(dim), 12usize.into()); 159 | assert_eq!(x.to_index(dim, &conv_pos((0, 1))), 0usize.into()); 160 | assert_eq!(x.to_index(dim, &conv_pos((1, 0))), 1usize.into()); 161 | assert_eq!(x.to_index(dim, &conv_pos((0, 2))), 2usize.into()); 162 | assert_eq!(x.to_index(dim, &conv_pos((2, 0))), 3usize.into()); 163 | assert_eq!(x.to_index(dim, &conv_pos((1, 2))), 4usize.into()); 164 | assert_eq!(x.to_index(dim, &conv_pos((2, 1))), 5usize.into()); 165 | assert_eq!(x.to_index(dim, &conv_pos((0, 3))), 6usize.into()); 166 | let mut new_pos = x.zero(dim); 167 | x.to_pos(dim, 6usize.into(), &mut new_pos); 168 | assert_eq!(new_pos, conv_pos((0, 3))); 169 | x.to_pos(dim, 5usize.into(), &mut new_pos); 170 | assert_eq!(new_pos, conv_pos((2, 1))); 171 | } 172 | 173 | #[test] 174 | fn of() { 175 | let x: NeqPair> = Construct::new(); 176 | let ref dim = vec![2, 2]; 177 | assert_eq!(x.count(dim), 12); 178 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0); 179 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 2); 180 | assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 4); 181 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 6); 182 | assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 8); 183 | assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 10); 184 | let mut pos = (Vec::new(), Vec::new()); 185 | for i in 0..6 { 186 | x.to_pos(dim, i, &mut pos); 187 | // println!("{} {}", &min[], &max[]); 188 | } 189 | x.to_pos(dim, 10, &mut pos); 190 | assert_eq!(&pos.0, &[0, 1]); 191 | assert_eq!(&pos.1, &[1, 1]); 192 | } 193 | 194 | fn conv(v: Vec) -> Vec { 195 | v.into_iter().map(|n| n.into()).collect() 196 | } 197 | 198 | fn conv_pos_of((a, b): (Vec, Vec)) -> (Vec, Vec) { 199 | (conv(a), conv(b)) 200 | } 201 | 202 | #[test] 203 | fn of_big() { 204 | let x: NeqPair> = Construct::new(); 205 | let ref dim = conv(vec![2, 2]); 206 | assert_eq!(x.count(dim), 12usize.into()); 207 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![1, 0]))), 0usize.into()); 208 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![0, 1]))), 2usize.into()); 209 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![1, 0], vec![0, 1]))), 4usize.into()); 210 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![1, 1]))), 6usize.into()); 211 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![1, 0], vec![1, 1]))), 8usize.into()); 212 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 1], vec![1, 1]))), 10usize.into()); 213 | let mut pos = x.zero(dim); 214 | for i in 0usize..6 { 215 | x.to_pos(dim, i.into(), &mut pos); 216 | // println!("{} {}", &min[], &max[]); 217 | assert_eq!(x.to_index(dim, &pos), i.into()); 218 | } 219 | x.to_pos(dim, 10usize.into(), &mut pos); 220 | assert_eq!(pos, conv_pos_of((vec![0, 1], vec![1, 1]))); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/pair.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use space::Space; 9 | 10 | /// Dimension is natural number, position is (min, max). 11 | pub struct Pair(PhantomData); 12 | 13 | impl Construct for Pair { 14 | fn new() -> Self { Pair(PhantomData) } 15 | } 16 | 17 | impl Space for Pair { 18 | type Dim = usize; 19 | type Pos = (usize, usize); 20 | fn count(&self, dim: &usize) -> usize { dim * (dim - 1) / 2 } 21 | fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) } 22 | fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize { 23 | if max == 0 {0} else { 24 | min + max * (max - 1) / 2 25 | } 26 | } 27 | fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) { 28 | use num::integer::Roots; 29 | let index = index as u128; 30 | let max = (1 + (8 * index + 1).sqrt()) / 2; 31 | let d = max * (max + 1) / 2; 32 | let min = (index).wrapping_add(max).wrapping_sub(d); 33 | *pos = (min as usize, max as usize) 34 | } 35 | } 36 | 37 | impl Space for Pair { 38 | type Dim = BigUint; 39 | type Pos = (BigUint, BigUint); 40 | fn count(&self, dim: &BigUint) -> BigUint { 41 | dim * (dim - 1usize) / 2usize 42 | } 43 | fn zero(&self, _dim: &BigUint) -> (BigUint, BigUint) { (0usize.into(), 0usize.into()) } 44 | fn to_index(&self, _dim: &Self::Dim, (min, max): &Self::Pos) -> BigUint { 45 | let _0 = 0usize.into(); 46 | if max == &_0 {_0} 47 | else { 48 | min + max * (max - 1usize) / 2usize 49 | } 50 | } 51 | fn to_pos(&self, _dim: &BigUint, index: BigUint, pos: &mut (BigUint, BigUint)) { 52 | let max: BigUint = (1usize + (8usize * &index + 1usize).sqrt()) / 2usize; 53 | let d = &max * (&max + 1usize) / 2usize; 54 | let min = &index + &max - d; 55 | *pos = (min, max) 56 | } 57 | } 58 | 59 | impl Space for Pair> 60 | where T: Space, 61 | Pair: Space, 62 | { 63 | type Dim = T::Dim; 64 | type Pos = (T::Pos, T::Pos); 65 | fn count(&self, dim: &Self::Dim) -> N { 66 | let of: T = Construct::new(); 67 | let data: Pair = Construct::new(); 68 | data.count(&of.count(dim)) 69 | } 70 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 71 | let of: T = Construct::new(); 72 | (of.zero(dim), of.zero(dim)) 73 | } 74 | fn to_index( 75 | &self, 76 | dim: &Self::Dim, 77 | &(ref min, ref max): &Self::Pos, 78 | ) -> N { 79 | let of: T = Construct::new(); 80 | let data: Pair = Construct::new(); 81 | let min = of.to_index(dim, min); 82 | let max = of.to_index(dim, max); 83 | data.to_index(&self.count(dim), &(min, max)) 84 | } 85 | fn to_pos( 86 | &self, 87 | dim: &Self::Dim, 88 | index: N, 89 | &mut (ref mut min, ref mut max): &mut Self::Pos, 90 | ) { 91 | let of: T = Construct::new(); 92 | let data: Pair = Construct::new(); 93 | let count = of.count(dim); 94 | let mut pair = data.zero(&count); 95 | data.to_pos(&count, index, &mut pair); 96 | let (pair_min, pair_max) = pair; 97 | of.to_pos(dim, pair_min, min); 98 | of.to_pos(dim, pair_max, max); 99 | } 100 | } 101 | 102 | #[cfg(test)] 103 | mod tests { 104 | use crate::*; 105 | 106 | #[test] 107 | fn features() { 108 | is_complete::(); 109 | is_complete::>>(); 110 | } 111 | 112 | #[test] 113 | fn data() { 114 | let x: Pair = Construct::new(); 115 | let ref dim = 4; 116 | assert_eq!(x.count(dim), 6); 117 | assert_eq!(x.to_index(dim, &(0, 1)), 0); 118 | assert_eq!(x.to_index(dim, &(0, 2)), 1); 119 | assert_eq!(x.to_index(dim, &(1, 2)), 2); 120 | assert_eq!(x.to_index(dim, &(0, 3)), 3); 121 | let mut new_pos = (0, 0); 122 | x.to_pos(dim, 3, &mut new_pos); 123 | assert_eq!(new_pos, (0, 3)); 124 | } 125 | 126 | fn conv_pos((a, b): (usize, usize)) -> (BigUint, BigUint) { 127 | (a.into(), b.into()) 128 | } 129 | 130 | #[test] 131 | fn data_big() { 132 | let x: Pair = Construct::new(); 133 | let ref dim: BigUint = 4usize.into(); 134 | assert_eq!(x.count(dim), 6usize.into()); 135 | assert_eq!(x.to_index(dim, &conv_pos((0, 1))), 0usize.into()); 136 | assert_eq!(x.to_index(dim, &conv_pos((0, 2))), 1usize.into()); 137 | assert_eq!(x.to_index(dim, &conv_pos((1, 2))), 2usize.into()); 138 | assert_eq!(x.to_index(dim, &conv_pos((0, 3))), 3usize.into()); 139 | let mut new_pos = x.zero(dim); 140 | x.to_pos(dim, 3usize.into(), &mut new_pos); 141 | assert_eq!(new_pos, conv_pos((0, 3))); 142 | } 143 | 144 | #[test] 145 | fn of() { 146 | let x: Pair> = Construct::new(); 147 | let ref dim = vec![2, 2]; 148 | assert_eq!(x.count(dim), 6); 149 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0); 150 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 1); 151 | assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 2); 152 | assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 3); 153 | assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 4); 154 | assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 5); 155 | let mut pos = (Vec::new(), Vec::new()); 156 | for i in 0..6 { 157 | x.to_pos(dim, i, &mut pos); 158 | // println!("{} {}", &min[], &max[]); 159 | } 160 | x.to_pos(dim, 5, &mut pos); 161 | assert_eq!(&pos.0, &[0, 1]); 162 | assert_eq!(&pos.1, &[1, 1]); 163 | } 164 | 165 | fn conv(v: Vec) -> Vec { 166 | v.into_iter().map(|n| n.into()).collect() 167 | } 168 | 169 | fn conv_pos_of((a, b): (Vec, Vec)) -> (Vec, Vec) { 170 | (conv(a), conv(b)) 171 | } 172 | 173 | #[test] 174 | fn of_big() { 175 | let x: Pair> = Construct::new(); 176 | let ref dim = conv(vec![2, 2]); 177 | assert_eq!(x.count(dim), 6usize.into()); 178 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![1, 0]))), 0usize.into()); 179 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![0, 1]))), 1usize.into()); 180 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![1, 0], vec![0, 1]))), 2usize.into()); 181 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 0], vec![1, 1]))), 3usize.into()); 182 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![1, 0], vec![1, 1]))), 4usize.into()); 183 | assert_eq!(x.to_index(dim, &conv_pos_of((vec![0, 1], vec![1, 1]))), 5usize.into()); 184 | let mut pos = x.zero(dim); 185 | for i in 0usize..6 { 186 | x.to_pos(dim, i.into(), &mut pos); 187 | // println!("{} {}", &min[], &max[]); 188 | assert_eq!(x.to_index(dim, &pos), i.into()); 189 | } 190 | x.to_pos(dim, 5usize.into(), &mut pos); 191 | assert_eq!(pos, conv_pos_of((vec![0, 1], vec![1, 1]))); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/permutation.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::marker::PhantomData; 3 | use std::ops::{ 4 | AddAssign, 5 | MulAssign, 6 | Sub, 7 | Mul, 8 | SubAssign, 9 | DivAssign, 10 | Div, 11 | }; 12 | use std::convert::TryInto; 13 | use std::fmt::Debug; 14 | 15 | use num::BigUint; 16 | 17 | use Construct; 18 | use Data; 19 | use Of; 20 | use space::Space; 21 | 22 | /// Dimension is natural number, position is a list of numbers. 23 | pub struct Permutation(PhantomData); 24 | 25 | impl Construct for Permutation { 26 | fn new() -> Self { Permutation(PhantomData) } 27 | } 28 | 29 | impl Space for Permutation { 30 | type Dim = usize; 31 | type Pos = Vec; 32 | fn count(&self, dim: &usize) -> usize { 33 | let mut res = 1; 34 | for x in 1..dim + 1 { 35 | res *= x; 36 | } 37 | res 38 | } 39 | fn zero(&self, dim: &usize) -> Vec { 40 | vec![0; *dim] 41 | } 42 | fn to_index(&self, dim: &usize, pos: &Vec) -> usize { 43 | let mut index = 0; 44 | let mut count = 1; 45 | for (i, &x) in pos.iter().enumerate().rev() { 46 | let lower = pos[..i].iter().filter(|&&y| y < x).count(); 47 | index += count * (x - lower); 48 | count *= dim - i; 49 | } 50 | index 51 | } 52 | fn to_pos(&self, dim: &usize, mut index: usize, pos: &mut Vec) { 53 | unsafe { pos.set_len(0); } 54 | 55 | let mut count = 1; 56 | for (j, x) in (1..dim + 1).enumerate() { 57 | count *= x; 58 | pos.push(j); 59 | } 60 | 61 | for i in 0..*dim { 62 | let block = count / (dim - i); 63 | let ind = index / block; 64 | let item = pos.remove(ind); 65 | pos.push(item); 66 | count /= dim - i; 67 | index -= ind * block; 68 | } 69 | } 70 | } 71 | 72 | impl Space for Permutation { 73 | type Dim = BigUint; 74 | type Pos = Vec; 75 | fn count(&self, dim: &BigUint) -> BigUint { 76 | let _1: BigUint = 1usize.into(); 77 | let mut res: BigUint = _1.clone(); 78 | let mut x = _1.clone(); 79 | loop { 80 | if &x > dim {break} 81 | res *= &x; 82 | x += &_1; 83 | } 84 | res 85 | } 86 | fn zero(&self, dim: &BigUint) -> Vec { 87 | let dim: usize = dim.try_into().unwrap(); 88 | vec![0usize.into(); dim] 89 | } 90 | fn to_index(&self, dim: &Self::Dim, pos: &Self::Pos) -> BigUint { 91 | let mut index: BigUint = 0usize.into(); 92 | let mut count: BigUint = 1usize.into(); 93 | for (i, x) in pos.iter().enumerate().rev() { 94 | let lower = pos[..i].iter().filter(|&y| y < x).count(); 95 | index += &count * (x - lower); 96 | count *= dim - i; 97 | } 98 | index 99 | } 100 | fn to_pos(&self, dim: &Self::Dim, mut index: BigUint, pos: &mut Self::Pos) { 101 | pos.clear(); 102 | 103 | let mut count: BigUint = 1usize.into(); 104 | let dim: usize = dim.try_into().unwrap(); 105 | for (j, x) in (1usize..dim + 1).enumerate() { 106 | count *= x; 107 | pos.push(j.into()); 108 | } 109 | 110 | let dim: usize = dim.try_into().unwrap(); 111 | for i in 0..dim { 112 | let block = &count / (dim - i); 113 | let ind: BigUint = &index / █ 114 | let item = pos.remove((&ind).try_into().unwrap()); 115 | pos.push(item); 116 | count /= dim - i; 117 | index -= &ind * block; 118 | } 119 | } 120 | } 121 | 122 | impl Space for Permutation> 123 | where T: Space, 124 | T::Pos: Clone, 125 | N: Clone + 126 | From + 127 | TryInto + 128 | for<'a> AddAssign<&'a N> + 129 | for<'a> MulAssign<&'a N> + 130 | Sub + 131 | SubAssign + 132 | DivAssign + 133 | MulAssign + 134 | PartialOrd, 135 | >::Error: Debug, 136 | for<'a> &'a N: Sub + 137 | Mul<&'a N, Output = N> + 138 | Div + 139 | Div<&'a N, Output = N> +, 140 | >::Error: Debug, 141 | { 142 | type Dim = T::Dim; 143 | type Pos = Vec; 144 | fn count(&self, dim: &Self::Dim) -> N { 145 | let of: T = Construct::new(); 146 | let _1: N = 1usize.into(); 147 | let mut x = _1.clone(); 148 | let mut res = _1.clone(); 149 | let of_count = of.count(dim); 150 | loop { 151 | if &x > &of_count {break} 152 | res *= &x; 153 | x += &_1; 154 | } 155 | res 156 | } 157 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 158 | let of: T = Construct::new(); 159 | let count = match of.count(dim).try_into() { 160 | Ok(x) => x, 161 | Err(_) => panic!("Out of range"), 162 | }; 163 | vec![of.zero(dim); count] 164 | } 165 | fn to_index(&self, dim: &Self::Dim, pos: &Self::Pos) -> N { 166 | let of: T = Construct::new(); 167 | let mut index: N = 0usize.into(); 168 | let dim_count = of.count(dim); 169 | let mut count: N = 1usize.into(); 170 | for (i, x) in pos.iter() 171 | .map(|x| of.to_index(dim, x)) 172 | .enumerate().rev() { 173 | let lower = pos[..i].iter() 174 | .map(|y| of.to_index(dim, y)) 175 | .filter(|y| y < &x).count(); 176 | index += &(&count * &(x - lower)); 177 | count *= &(&dim_count - i); 178 | } 179 | index 180 | } 181 | fn to_pos(&self, dim: &Self::Dim, mut index: N, pos: &mut Self::Pos) { 182 | let of: T = Construct::new(); 183 | let of_count: usize = of.count(dim).try_into().unwrap(); 184 | pos.clear(); 185 | 186 | let mut count: N = 1usize.into(); 187 | for (j, x) in (1..of_count + 1).enumerate() { 188 | count *= x; 189 | let mut new_pos: T::Pos = of.zero(&dim); 190 | of.to_pos(dim, j.into(), &mut new_pos); 191 | pos.push(new_pos); 192 | } 193 | 194 | for i in 0..of_count { 195 | let diff = of_count - i; 196 | let block = &count / diff; 197 | let ind = &index / █ 198 | index -= &ind * █ 199 | let item = pos.remove(ind.try_into().unwrap()); 200 | pos.push(item); 201 | count /= diff; 202 | } 203 | } 204 | } 205 | 206 | #[cfg(test)] 207 | mod test { 208 | use super::super::*; 209 | 210 | #[test] 211 | fn features() { 212 | is_complete::(); 213 | is_complete::>>(); 214 | } 215 | 216 | #[test] 217 | fn data() { 218 | let permutation: Permutation = Construct::new(); 219 | assert_eq!(permutation.count(&1), 1); 220 | assert_eq!(permutation.count(&2), 2); 221 | assert_eq!(permutation.count(&3), 6); 222 | assert_eq!(permutation.count(&4), 24); 223 | 224 | let mut pos = Vec::new(); 225 | let ref dim = 4; 226 | let count = permutation.count(dim); 227 | for i in 0..count { 228 | permutation.to_pos(dim, i, &mut pos); 229 | let index = permutation.to_index(dim, &pos); 230 | assert_eq!(index, i); 231 | } 232 | } 233 | 234 | #[test] 235 | fn data_big() { 236 | use std::convert::TryInto; 237 | 238 | let permutation: Permutation = Construct::new(); 239 | let ins: Vec = vec![ 240 | 1usize.into(), 241 | 2usize.into(), 242 | 3usize.into(), 243 | 4usize.into(), 244 | ]; 245 | let outs: Vec = vec![ 246 | 1usize.into(), 247 | 2usize.into(), 248 | 6usize.into(), 249 | 24usize.into(), 250 | ]; 251 | for i in 0..ins.len() { 252 | assert_eq!(permutation.count(&ins[i]), outs[i]); 253 | } 254 | 255 | let mut pos: Vec = Vec::new(); 256 | let ref dim: BigUint = 4usize.into(); 257 | let count: usize = permutation.count(dim).try_into().unwrap(); 258 | for i in 0usize..count { 259 | permutation.to_pos(dim, i.into(), &mut pos); 260 | let index = permutation.to_index(dim, &pos); 261 | assert_eq!(index, i.into()); 262 | } 263 | } 264 | 265 | #[test] 266 | fn of() { 267 | let space: Permutation> = Construct::new(); 268 | let ref dim = 3; 269 | let count = space.count(dim); 270 | let mut pos = space.zero(dim); 271 | for i in 0..count { 272 | space.to_pos(dim, i, &mut pos); 273 | let index = space.to_index(dim, &pos); 274 | assert_eq!(index, i); 275 | } 276 | } 277 | 278 | #[test] 279 | fn of_big() { 280 | use std::convert::TryInto; 281 | 282 | let space: Permutation> = Construct::new(); 283 | let ref dim: BigUint = 3usize.into(); 284 | let count: usize = space.count(dim).try_into().unwrap(); 285 | let mut pos = space.zero(dim); 286 | for i in 0..count { 287 | space.to_pos(dim, i.into(), &mut pos); 288 | let index = space.to_index(dim, &pos); 289 | assert_eq!(index, i.into()); 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/power_set.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::convert::TryInto; 3 | use std::fmt::Debug; 4 | 5 | use std::ops::{BitOrAssign, Rem, Shr}; 6 | 7 | use num::BigUint; 8 | use num::pow::Pow; 9 | 10 | use Construct; 11 | use Of; 12 | use Data; 13 | use space::Space; 14 | 15 | /// Dimension is natural number, position is a list of numbers. 16 | pub struct PowerSet(PhantomData); 17 | 18 | impl Construct for PowerSet { 19 | fn new() -> Self { PowerSet(PhantomData) } 20 | } 21 | 22 | impl Space for PowerSet { 23 | type Dim = usize; 24 | type Pos = Vec; 25 | fn count(&self, dim: &usize) -> usize { 26 | 1 << *dim 27 | } 28 | fn zero(&self, _dim: &usize) -> Vec { 29 | vec![] 30 | } 31 | fn to_index( 32 | &self, 33 | _dim: &usize, 34 | pos: &Vec 35 | ) -> usize { 36 | let mut index = 0; 37 | for &i in pos.iter() { 38 | index |= 1 << i; 39 | } 40 | index 41 | } 42 | fn to_pos( 43 | &self, 44 | dim: &usize, 45 | index: usize, 46 | pos: &mut Vec 47 | ) { 48 | unsafe { pos.set_len(0); } 49 | for i in 0..*dim { 50 | if ((index >> i) & 1) == 1 { 51 | pos.push(i); 52 | } 53 | } 54 | } 55 | } 56 | 57 | impl Space for PowerSet { 58 | type Dim = BigUint; 59 | type Pos = Vec; 60 | fn count(&self, dim: &BigUint) -> BigUint { 61 | let _two: BigUint = 2usize.into(); 62 | let dim: u32 = dim.try_into().unwrap(); 63 | _two.pow(dim) 64 | } 65 | fn zero(&self, _dim: &BigUint) -> Vec { 66 | vec![] 67 | } 68 | fn to_index( 69 | &self, 70 | _dim: &Self::Dim, 71 | pos: &Self::Pos, 72 | ) -> BigUint { 73 | let mut index: BigUint = 0usize.into(); 74 | let ref _2: BigUint = 2usize.into(); 75 | for i in pos { 76 | index |= _2.pow(i.try_into().unwrap()); 77 | } 78 | index 79 | } 80 | fn to_pos( 81 | &self, 82 | dim: &Self::Dim, 83 | index: BigUint, 84 | pos: &mut Self::Pos, 85 | ) { 86 | pos.clear(); 87 | let dim: u32 = dim.try_into().unwrap(); 88 | let ref _2: BigUint = 2u32.into(); 89 | let ref _1: BigUint = 1u32.into(); 90 | for i in 0u32..dim { 91 | if &((&index >> i) % _2) == _1 { 92 | pos.push(i.into()); 93 | } 94 | } 95 | } 96 | } 97 | 98 | impl Space for PowerSet> 99 | where T: Space, 100 | N: Clone + 101 | From + 102 | PartialEq + 103 | TryInto + 104 | BitOrAssign + 105 | Rem + 106 | Pow + 107 | Shr, 108 | >::Error: Debug, 109 | { 110 | type Dim = T::Dim; 111 | type Pos = Vec; 112 | fn count(&self, dim: &Self::Dim) -> N { 113 | let _two: N = 2usize.into(); 114 | let of: T = Construct::new(); 115 | let count = of.count(dim); 116 | _two.pow(count.try_into().unwrap()) 117 | } 118 | fn zero(&self, _dim: &Self::Dim) -> Self::Pos { 119 | vec![] 120 | } 121 | fn to_index( 122 | &self, 123 | dim: &Self::Dim, 124 | pos: &Self::Pos, 125 | ) -> N { 126 | let of: T = Construct::new(); 127 | let mut index: N = 0usize.into(); 128 | let _2: N = 2usize.into(); 129 | for i in pos { 130 | let i: N = of.to_index(dim, i); 131 | index |= _2.clone().pow(i.try_into().unwrap()); 132 | } 133 | index 134 | } 135 | fn to_pos( 136 | &self, 137 | dim: &Self::Dim, 138 | index: N, 139 | pos: &mut Self::Pos, 140 | ) { 141 | let of: T = Construct::new(); 142 | let count = of.count(dim); 143 | pos.clear(); 144 | let count: u32 = count.try_into().unwrap(); 145 | pos.reserve_exact(count as usize); 146 | let ref _1: N = 1usize.into(); 147 | for j in 0u32..count { 148 | if &((index.clone() >> j) % 2) == _1 { 149 | let mut p = of.zero(dim); 150 | of.to_pos(dim, (j as usize).into(), &mut p); 151 | pos.push(p); 152 | } 153 | } 154 | } 155 | } 156 | 157 | #[cfg(test)] 158 | mod tests { 159 | use super::super::*; 160 | 161 | #[test] 162 | fn features() { 163 | is_complete::(); 164 | is_complete::>>(); 165 | } 166 | 167 | #[test] 168 | fn data() { 169 | let x: PowerSet = Construct::new(); 170 | let ref dim = 6; 171 | assert_eq!(x.count(dim), 64); 172 | assert_eq!(x.to_index(dim, &vec![]), 0); 173 | assert_eq!(x.to_index(dim, &vec![0]), 1); 174 | assert_eq!(x.to_index(dim, &vec![1]), 2); 175 | assert_eq!(x.to_index(dim, &vec![0, 1]), 3); 176 | let mut a = vec![]; 177 | x.to_pos(dim, 9, &mut a); 178 | assert_eq!(&a, &[0, 3]); 179 | } 180 | 181 | fn conv(v: Vec) -> Vec { 182 | v.into_iter().map(|n| n.into()).collect() 183 | } 184 | 185 | #[test] 186 | fn data_big() { 187 | let x: PowerSet = Construct::new(); 188 | let ref dim: BigUint = 6usize.into(); 189 | assert_eq!(x.count(dim), 64usize.into()); 190 | assert_eq!(x.to_index(dim, &vec![]), 0usize.into()); 191 | assert_eq!(x.to_index(dim, &conv(vec![0])), 1usize.into()); 192 | assert_eq!(x.to_index(dim, &conv(vec![1])), 2usize.into()); 193 | assert_eq!(x.to_index(dim, &conv(vec![0, 1])), 3usize.into()); 194 | let mut a = vec![]; 195 | x.to_pos(dim, 9usize.into(), &mut a); 196 | assert_eq!(a, conv(vec![0, 3])); 197 | } 198 | 199 | #[test] 200 | fn of() { 201 | let x: PowerSet> = Construct::new(); 202 | let ref dim = 4; 203 | assert_eq!(x.count(dim), 64); 204 | assert_eq!(x.to_index(dim, &vec![]), 0); 205 | assert_eq!(x.to_index(dim, &vec![(0, 1)]), 1); 206 | assert_eq!(x.to_index(dim, &vec![(0, 2)]), 2); 207 | assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3); 208 | assert_eq!(x.to_index(dim, &vec![(1, 2)]), 4); 209 | assert_eq!(x.to_index(dim, &vec![(0, 1), (1, 2)]), 5); 210 | assert_eq!(x.to_index(dim, &vec![(0, 2), (1, 2)]), 6); 211 | assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2), (1, 2)]), 7); 212 | let mut a = vec![(0, 0); 64]; 213 | x.to_pos(dim, 7, &mut a); 214 | assert_eq!(a[0], (0, 1)); 215 | } 216 | 217 | fn conv_pos_of(v: Vec<(usize, usize)>) -> Vec<(BigUint, BigUint)> { 218 | v.into_iter().map(|(a, b)| (a.into(), b.into())).collect() 219 | } 220 | 221 | #[test] 222 | fn of_big() { 223 | let x: PowerSet> = Construct::new(); 224 | let ref dim: BigUint = 4usize.into(); 225 | assert_eq!(x.count(dim), 64usize.into()); 226 | assert_eq!(x.to_index(dim, &vec![]), 0usize.into()); 227 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 1)])), 1usize.into()); 228 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 2)])), 2usize.into()); 229 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 1), (0, 2)])), 3usize.into()); 230 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(1, 2)])), 4usize.into()); 231 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 1), (1, 2)])), 5usize.into()); 232 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 2), (1, 2)])), 6usize.into()); 233 | assert_eq!(x.to_index(dim, &conv_pos_of(vec![(0, 1), (0, 2), (1, 2)])), 7usize.into()); 234 | let mut a = conv_pos_of(vec![(0, 0); 64]); 235 | x.to_pos(dim, 7usize.into(), &mut a); 236 | assert_eq!(a[0], (0usize.into(), 1usize.into())); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/space.rs: -------------------------------------------------------------------------------- 1 | //! Helper trait for implementing discrete spaces. 2 | 3 | use Construct; 4 | use Count; 5 | use Zero; 6 | use ToIndex; 7 | use ToPos; 8 | 9 | use BigUint; 10 | 11 | /// Implemented by discrete spaces. 12 | pub trait Space: Construct + Sized { 13 | /// The dimension type of the space. 14 | type Dim; 15 | /// The position type of the space. 16 | type Pos; 17 | 18 | /// Counts the size of space given the dimensions. 19 | fn count(&self, dim: &Self::Dim) -> N; 20 | /// Creates a default element. 21 | fn zero(&self, dim: &Self::Dim) -> Self::Pos; 22 | /// Converts position to index. 23 | fn to_index(&self, dim: &Self::Dim, pos: &Self::Pos) -> N; 24 | /// Converts index to position. 25 | fn to_pos(&self, dim: &Self::Dim, index: N, pos: &mut Self::Pos); 26 | } 27 | 28 | impl> Count for T { 29 | fn count(&self, dim: &D) -> usize {Space::::count(self, dim)} 30 | } 31 | 32 | impl> Count for T { 33 | fn count(&self, dim: &D) -> BigUint {Space::::count(self, dim)} 34 | } 35 | 36 | impl> Zero for T { 37 | fn zero(&self, dim: &D) -> P {Space::::zero(self, dim)} 38 | } 39 | 40 | impl> Zero for T { 41 | fn zero(&self, dim: &D) -> P {Space::::zero(self, dim)} 42 | } 43 | 44 | impl> ToIndex for T { 45 | fn to_index(&self, dim: &D, pos: &P) -> usize {Space::::to_index(self, dim, pos)} 46 | } 47 | 48 | impl> ToIndex for T { 49 | fn to_index(&self, dim: &D, pos: &P) -> BigUint {Space::::to_index(self, dim, pos)} 50 | } 51 | 52 | impl> ToPos for T { 53 | fn to_pos(&self, dim: &D, ind: usize, pos: &mut P) {Space::::to_pos(self, dim, ind, pos)} 54 | } 55 | 56 | impl> ToPos for T { 57 | fn to_pos(&self, dim: &D, ind: BigUint, pos: &mut P) {Space::::to_pos(self, dim, ind, pos)} 58 | } 59 | -------------------------------------------------------------------------------- /src/sq_pair.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use num::BigUint; 4 | 5 | use Construct; 6 | use Data; 7 | use Of; 8 | use space::Space; 9 | 10 | /// A discrete space that models a full square of NxN pairs. 11 | /// 12 | /// Dimension is natural number, position is `(x, y)`. 13 | pub struct SqPair(PhantomData); 14 | 15 | impl Construct for SqPair { 16 | fn new() -> Self {SqPair(PhantomData)} 17 | } 18 | 19 | impl Space for SqPair { 20 | type Dim = usize; 21 | type Pos = (usize, usize); 22 | fn count(&self, dim: &usize) -> usize {dim * dim} 23 | fn zero(&self, _: &usize) -> (usize, usize) {(0, 0)} 24 | fn to_index(&self, dim: &usize, &(a, b): &(usize, usize)) -> usize { 25 | a + b * dim 26 | } 27 | fn to_pos(&self, dim: &usize, index: usize, pos: &mut (usize, usize)) { 28 | pos.0 = index % dim; 29 | pos.1 = index / dim; 30 | } 31 | } 32 | 33 | impl Space for SqPair { 34 | type Dim = BigUint; 35 | type Pos = (BigUint, BigUint); 36 | fn count(&self, dim: &Self::Dim) -> BigUint {dim * dim} 37 | fn zero(&self, _: &Self::Dim) -> Self::Pos {(0usize.into(), 0usize.into())} 38 | fn to_index(&self, dim: &Self::Dim, (a, b): &Self::Pos) -> BigUint { 39 | a + b * dim 40 | } 41 | fn to_pos(&self, dim: &Self::Dim, index: BigUint, pos: &mut Self::Pos) { 42 | pos.0 = &index % dim; 43 | pos.1 = &index / dim; 44 | } 45 | } 46 | 47 | impl Space for SqPair> 48 | where T: Space, 49 | N: From, 50 | SqPair: Space, 51 | { 52 | type Dim = T::Dim; 53 | type Pos = (T::Pos, T::Pos); 54 | fn count(&self, dim: &Self::Dim) -> N { 55 | let of: T = Construct::new(); 56 | let data: SqPair = Construct::new(); 57 | data.count(&of.count(dim)) 58 | } 59 | fn zero(&self, dim: &Self::Dim) -> Self::Pos { 60 | let of: T = Construct::new(); 61 | (of.zero(dim), of.zero(dim)) 62 | } 63 | fn to_index( 64 | &self, 65 | dim: &Self::Dim, 66 | &(ref a, ref b): &Self::Pos 67 | ) -> N { 68 | let of: T = Construct::new(); 69 | let data: SqPair = Construct::new(); 70 | let a = of.to_index(dim, a); 71 | let b = of.to_index(dim, b); 72 | data.to_index(&self.count(dim), &(a, b)) 73 | } 74 | fn to_pos( 75 | &self, 76 | dim: &Self::Dim, 77 | index: N, 78 | &mut (ref mut a, ref mut b): &mut Self::Pos 79 | ) { 80 | let of: T = Construct::new(); 81 | let data: SqPair = Construct::new(); 82 | let count = of.count(dim); 83 | let mut pair = (0usize.into(), 0usize.into()); 84 | data.to_pos(&count, index, &mut pair); 85 | let (pair_a, pair_b) = pair; 86 | of.to_pos(dim, pair_a, a); 87 | of.to_pos(dim, pair_b, b); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/subspace.rs: -------------------------------------------------------------------------------- 1 | //! Implements traits for tuples such that subspaces can be constructed. 2 | 3 | use std::ops::{Mul, Div, Sub, Add}; 4 | 5 | use Construct; 6 | use space::Space; 7 | 8 | impl Construct for (T, U) 9 | where T: Construct, U: Construct, 10 | { 11 | fn new() -> Self { (Construct::new(), Construct::new()) } 12 | } 13 | 14 | impl Space for (T, U) 15 | where T: Space, 16 | U: Space, 17 | N: Add, 18 | for<'a> &'a N: Mul<&'a N, Output = N> + 19 | Div<&'a N, Output = N> + 20 | Sub<&'a N, Output = N>, 21 | { 22 | type Dim = (T::Dim, U::Dim); 23 | type Pos = (T::Pos, U::Pos); 24 | fn count(&self, &(ref dim_t, ref dim_u): &Self::Dim) -> N { 25 | let t: T = Construct::new(); 26 | let u: U = Construct::new(); 27 | &t.count(dim_t) * &u.count(dim_u) 28 | } 29 | fn zero(&self, &(ref dim_t, ref dim_u): &Self::Dim) -> Self::Pos { 30 | let t: T = Construct::new(); 31 | let u: U = Construct::new(); 32 | (t.zero(dim_t), u.zero(dim_u)) 33 | } 34 | fn to_index( 35 | &self, 36 | &(ref dim_t, ref dim_u): &Self::Dim, 37 | &(ref pt, ref pu): &Self::Pos, 38 | ) -> N { 39 | let t: T = Construct::new(); 40 | let u: U = Construct::new(); 41 | let count = u.count(dim_u); 42 | &t.to_index(dim_t, pt) * &count + u.to_index(dim_u, pu) 43 | } 44 | fn to_pos( 45 | &self, 46 | &(ref dim_t, ref dim_u): &Self::Dim, 47 | ind: N, 48 | &mut (ref mut pt, ref mut pu): &mut Self::Pos, 49 | ) { 50 | let t: T = Construct::new(); 51 | let u: U = Construct::new(); 52 | let count = u.count(dim_u); 53 | let x = &ind / &count; 54 | u.to_pos(dim_u, &ind - &(&x * &count), pu); 55 | t.to_pos(dim_t, x, pt); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/to_index.rs: -------------------------------------------------------------------------------- 1 | /// Implemented by spaces that can convert position to index. 2 | pub trait ToIndex { 3 | /// Converts position to index. 4 | fn to_index(&self, dim: &T, pos: &U) -> N; 5 | } 6 | -------------------------------------------------------------------------------- /src/to_pos.rs: -------------------------------------------------------------------------------- 1 | /// Implemented for spaces which can convert an index to position type. 2 | pub trait ToPos { 3 | /// Converts index to position. 4 | fn to_pos(&self, dim: &T, index: N, pos: &mut U); 5 | } 6 | -------------------------------------------------------------------------------- /src/zero.rs: -------------------------------------------------------------------------------- 1 | /// Used to construct an uninitialized element of a discrete space. 2 | pub trait Zero { 3 | /// Creates a default element. 4 | fn zero(&self, dim: &T) -> U; 5 | } 6 | --------------------------------------------------------------------------------