pub mod permutation;
pub mod free;
pub mod tree;
pub mod special;
pub mod calculation;
use std::hash::Hash;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::fmt::{Display, Formatter, Error};
use self::calculation::identity;
pub trait GroupElement {
fn is_identity(&self) -> bool;
fn times(&self, multiplicant: &Self) -> Self;
fn inverse(&self) -> Self;
}
pub trait GroupAction {
type Domain;
fn act_on(&self, element: &Self::Domain) -> Self::Domain;
}
pub struct Group<Domain, G>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> + PartialEq {
levels: Vec<BaseStrongGeneratorLevel<Domain, G>>,
}
impl<Domain, G> Group<Domain, G>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> + PartialEq {
pub fn new(gset: Vec<Domain>, generators: Vec<G>) -> Group<Domain, G> {
let mut levels = vec!();
let mut gs = generators;
while gs.len() > 0 {
let base: Domain = find_base(&gset, &gs).expect("generators should move something");
let (level, stabilizers) = BaseStrongGeneratorLevel::new(base, gs);
levels.push(level);
gs = stabilizers;
}
Group { levels: levels }
}
pub fn size(&self) -> usize {
self.levels
.iter()
.fold(1usize, |acc, ref level| acc * level.length() )
}
pub fn is_member(&self, element: G) -> bool {
let candidate = self.strip(element);
candidate.is_identity()
}
pub fn strip(&self, element: G) -> G {
let mut candidate = element;
for level in &self.levels {
if level.has_transversal_for(&candidate) {
let transversal = level.transversal_for(&candidate).expect("should have transversal");
let inverse = transversal.inverse();
candidate = candidate.times(&inverse);
} else {
break;
}
}
candidate
}
}
fn find_base<Domain, G>(gset: &Vec<Domain>, generators: &Vec<G>) -> Option<Domain>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> {
for original in gset {
for generator in generators {
let image = generator.act_on(&original);
if &image != original {
return Some(image.clone())
}
}
}
None
}
impl<Domain, G> Display for Group<Domain, G>
where Domain: Eq + Hash + Clone + Display, G: GroupElement + GroupAction<Domain=Domain> + PartialEq + Display {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "<\n")?;
for level in &self.levels {
level.fmt(f)?;
}
write!(f, ">\n")
}
}
pub struct BaseStrongGeneratorLevel<Domain, G>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> + PartialEq {
base: Domain,
generators: Vec<G>,
indices: HashMap<Domain, isize>,
}
impl<Domain, G> BaseStrongGeneratorLevel<Domain, G>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> + PartialEq {
pub fn new(base: Domain, generators: Vec<G>) -> (Self, Vec<G>) {
let mut to_visit: VecDeque<Domain> = VecDeque::new();
let mut indices: HashMap<Domain, isize> = HashMap::new();
let mut stabilizers: Vec<G> = vec!();
to_visit.push_back(base.clone());
indices.insert(base.clone(), -1);
while !to_visit.is_empty() {
let element = to_visit.pop_front().unwrap();
for (index, generator) in generators.iter().enumerate() {
let image = generator.act_on(&element);
if !indices.contains_key(&image) {
indices.insert(image.clone(), index as isize);
to_visit.push_back(image.clone());
} else {
let to = transversal_for(&element, &generators, &indices).unwrap();
let fro = transversal_for(&image, &generators, &indices).unwrap().inverse();
let stabilizer = to.times(&generator).times(&fro);
if add_to_stabilizers(&stabilizer, &stabilizers) {
stabilizers.push(stabilizer);
}
}
}
}
(BaseStrongGeneratorLevel { base, generators, indices }, stabilizers)
}
pub fn has_transversal_for(&self, g: &G) -> bool {
let image = g.act_on(&self.base);
self.indices.contains_key(&image)
}
pub fn transversal_for(&self, g: &G) -> Option<G> {
let image = g.act_on(&self.base);
transversal_for(&image, &self.generators, &self.indices)
}
pub fn length(&self) -> usize {
self.indices.len()
}
}
fn add_to_stabilizers<Domain, G>(stabilizer: &G, stabilizers: &Vec<G>) -> bool
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> + PartialEq {
!stabilizer.is_identity() && !stabilizers.contains(&stabilizer)
}
impl<Domain, G> Display for BaseStrongGeneratorLevel<Domain, G>
where Domain: Eq + Hash + Clone + Display, G: GroupElement + GroupAction<Domain=Domain> + PartialEq + Display {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "[{};<", self.base)?;
for g in &self.generators {
write!(f, "{}", g)?;
}
write!(f, ">;")?;
for (domain, index) in &self.indices {
write!(f, "({}, {})", domain, index)?;
}
write!(f, "]\n")
}
}
fn transversal_for<Domain, G>(start: &Domain, generators: &Vec<G>, indices: &HashMap<Domain, isize>) -> Option<G>
where Domain: Eq + Hash + Clone, G: GroupElement + GroupAction<Domain=Domain> {
let mut image = start.clone();
if indices.contains_key(&image) {
let mut transversal = identity(&generators);
let mut index = indices.get(&image).unwrap();
while *index != (-1 as isize) {
let generator = &generators[(*index as usize)];
let inverse = generator.inverse();
image = inverse.act_on(&image);
transversal = transversal.times(&inverse);
index = indices.get(&image).unwrap();
}
Some(transversal.inverse())
} else {
None
}
}
#[macro_export]
macro_rules! morphism {
( $($from: expr, $to: expr),* ) => {
{
let mut morphism_images = HashMap::new();
$(
morphism_images.insert(SLP::Generator($from), Word::generator($to));
)*
Morphism::new(morphism_images)
}
}
}
pub struct Morphism<G, H>
where G: GroupElement + Eq + Hash, H: GroupElement + Eq + Hash {
generator_images: HashMap<G, H>
}
impl<G, H> Morphism<G, H>
where G: GroupElement + Eq + Hash, H: GroupElement + Eq + Hash + Clone {
pub fn new(generator_images: HashMap<G, H>) -> Morphism<G, H> {
Morphism { generator_images: generator_images }
}
pub fn transform(&self, element: &G) -> H {
self.generator_images.get(element).expect("should have an image").clone()
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::permutation::Permutation;
use super::*;
fn d3() -> Group<u64, Permutation> {
let mut transposition_images = HashMap::new();
transposition_images.insert(0u64, 1u64);
transposition_images.insert(1u64, 0u64);
transposition_images.insert(2u64, 2u64);
let transposition = Permutation::new(transposition_images);
let mut rotation_images = HashMap::new();
rotation_images.insert(0u64, 1u64);
rotation_images.insert(1u64, 2u64);
rotation_images.insert(2u64, 0u64);
let rotation = Permutation::new(rotation_images);
let gset = vec!(0u64, 1u64, 2u64);
let generators = vec!(transposition, rotation);
Group::new(gset, generators)
}
#[test]
fn group_should_have_a_size() {
let group = d3();
println!("{}", group);
assert_eq!(group.size(), 6);
}
#[test]
fn group_should_determine_if_an_element_is_a_member() {
let mut transposition_images = HashMap::new();
transposition_images.insert(0u64, 2u64);
transposition_images.insert(1u64, 1u64);
transposition_images.insert(2u64, 0u64);
let transposition = Permutation::new(transposition_images);
let group = d3();
assert!(group.is_member(transposition));
}
#[test]
fn transversal_for_should_correctly_determine_transversal() {
let image = 4u64;
let mut a_image: HashMap<u64, u64> = HashMap::new();
a_image.insert(0u64, 1u64);
a_image.insert(1u64, 2u64);
a_image.insert(2u64, 0u64);
a_image.insert(3u64, 4u64);
a_image.insert(4u64, 5u64);
a_image.insert(5u64, 3u64);
let a = Permutation::new(a_image);
let mut b_image: HashMap<u64, u64> = HashMap::new();
b_image.insert(0u64, 3u64);
b_image.insert(1u64, 1u64);
b_image.insert(2u64, 2u64);
b_image.insert(3u64, 0u64);
b_image.insert(4u64, 4u64);
b_image.insert(5u64, 5u64);
let b = Permutation::new(b_image);
let generators = vec!(a.clone(), b.clone());
let mut indices: HashMap<u64, isize> = HashMap::new();
indices.insert(0u64, -1isize);
indices.insert(1u64, 0isize);
indices.insert(2u64, 0isize);
indices.insert(3u64, 1isize);
indices.insert(4u64, 0isize);
indices.insert(5u64, 0isize);
let transversal = transversal_for(&image, &generators, &indices).unwrap();
let expected = b.times(&a);
assert_eq!(transversal, expected);
}
}