using System; using System.Collections.Generic; using System.Diagnostics; using CultureInfo = System.Globalization.CultureInfo; using DotNetTransformer.Extensions; using DotNetTransformer.Math.Group; using DotNetTransformer.Math.Permutation; using DotNetTransformer.Math.Set; namespace DotNetTransformer.Math.Transform { using T = FlipRotate16D; using P = PermutationInt64; [Serializable] [DebuggerDisplay("{ToString()}, CycleLength = {CycleLength}")] public struct FlipRotate16D : IFlipRotate { public readonly P Permutation; private readonly short _vertex; public FlipRotate16D(P permutation, int vertex) { Permutation = permutation; _vertex = (short)vertex; } public static T None { get { return new T(); } } public static T GetFlip(int dimension) { if((dimension & -_dimCount) != 0) throw new ArgumentOutOfRangeException("dimension"); return new T(new P(), 1 << dimension); } public static T GetRotate(int dimFrom, int dimTo) { if((dimFrom & -_dimCount) != 0) throw new ArgumentOutOfRangeException("dimFrom"); if((dimTo & -_dimCount) != 0) throw new ArgumentOutOfRangeException("dimTo"); if(dimFrom == dimTo) throw new ArgumentException( ); long x = dimFrom ^ dimTo; P p = new P((x << (dimFrom << 2)) ^ (x << (dimTo << 2))); return new T(p, 1 << dimTo); } private static IDictionary> _reflections; private static IDictionary> _rotations; private static IDictionary> _allValues; public static IFiniteSet GetReflections(int dimensions) { return GetValues>( dimensions, ref _reflections, dim => new ReflectionsSet(dim) ); } public static IFiniteGroup GetRotations(int dimensions) { return GetValues>( dimensions, ref _rotations, dim => new RotationsGroup(dim) ); } public static IFiniteGroup GetAllValues(int dimensions) { return GetValues>( dimensions, ref _allValues, dim => new FlipRotateGroup(dim) ); } private static S GetValues(int dimensions, ref IDictionary collection, Converter ctor ) where S : IFiniteSet { if(dimensions < 0 || dimensions > _dimCount) throw new ArgumentOutOfRangeException( ); byte dim = (byte)dimensions; if(ReferenceEquals(collection, null)) collection = new SortedList(_dimCount + 1); if(collection.ContainsKey(dim)) return collection[dim]; else { S r = ctor(dim); collection.Add(dim, r); return r; } } private abstract class FlipRotateSet : FiniteSet { protected readonly byte _dim; protected FlipRotateSet(byte dimensions) { _dim = dimensions; } protected bool IsRotational(int swaps, int vertex) { for(int i = 1; i < _dim; i <<= 1) vertex ^= vertex >> i; return ((swaps ^ vertex) & 1) == 0; } public override long Count { get { long c = 1L; for(byte i = 1; i < _dim; c *= ++i) ; return c << _dim; } } public override bool Contains(T item) { return item.Vertex >> _dim == 0 && item.Permutation.ReducibleTo(_dim); } public override IEnumerator GetEnumerator() { int c = 1 << _dim; P i = new P(); foreach(P p in i.GetRange

(i, _dim)) for(int v = 0; v < c; ++v) yield return new T(p, v); } } private class FlipRotateGroup : FlipRotateSet, IFiniteGroup { public FlipRotateGroup(byte dimensions) : base(dimensions) { } public T IdentityElement { get { return None; } } } private sealed class ReflectionsSet : FlipRotateSet { public ReflectionsSet(byte dimensions) : base(dimensions) { } public override long Count { get { return base.Count >> 1; } } public override bool Contains(T item) { return base.Contains(item) && item.IsReflection; } public override IEnumerator GetEnumerator() { int c = 1 << _dim; P i = new P(); foreach(P p in i.GetRange

(i, _dim)) { int s = p.SwapsCount; for(int v = 0; v < c; ++v) if(!IsRotational(s, v)) yield return new T(p, v); } } } private sealed class RotationsGroup : FlipRotateGroup { public RotationsGroup(byte dimensions) : base(dimensions) { } public override long Count { get { long c = base.Count; return c - (c >> 1); } } public override bool Contains(T item) { return base.Contains(item) && item.IsRotation; } public override IEnumerator GetEnumerator() { int c = 1 << _dim; P i = new P(); foreach(P p in i.GetRange

(i, _dim)) { int s = p.SwapsCount; for(int v = 0; v < c; ++v) if(IsRotational(s, v)) yield return new T(p, v); } } } private const byte _dimCount = 16; public bool IsReflection { get { return !IsRotation; } } public bool IsRotation { get { int v = _vertex; for(int i = 1; i < _dimCount; i <<= 1) v ^= v >> i; return ((Permutation.SwapsCount ^ v) & 1) == 0; } } P IFlipRotate.Permutation { get { return Permutation; } } public int Vertex { get { return _vertex & 0xFFFF; } } public int CycleLength { get { int c = Permutation.CycleLength; return GroupExtension.Times(this, c).Equals(None) ? c : (c << 1); } } public T InverseElement { get { P p = -Permutation; return new T(p, _vertex.GetPrev

(p)); } } public T Add(T other) { P p = Permutation; return new T(p + other.Permutation, _vertex ^ other._vertex.GetPrev

(p) ); } public T Subtract(T other) { P p = Permutation - other.Permutation; return new T(p, _vertex ^ other._vertex.GetPrev

(p) ); } public T Times(int count) { return FiniteGroupExtension.Times(this, count); } public override int GetHashCode() { return Permutation.GetHashCode() ^ Vertex; } public override bool Equals(object o) { return o is T && Equals((T)o); } public bool Equals(T o) { return Permutation == o.Permutation && _vertex == o._vertex; } public override string ToString() { return string.Format( CultureInfo.InvariantCulture, "P:{0} V:{1:X4}", Permutation, Vertex ); } /// /// /// Invalid . /// /// public static T FromString(string s) { if(ReferenceEquals(s, null)) throw new ArgumentNullException(); string[] ss = s.Trim().Split( (" ").ToCharArray(), StringSplitOptions.RemoveEmptyEntries ); int len = ss.GetLength(0); if(len != 2) throw new ArgumentException(); Dictionary dict = new Dictionary(); for(int j = 0; j < len; ++j) { int i = ss[j].IndexOf(':'); dict.Add(ss[j].Substring(0, i), ss[j].Substring(i + 1)); } return new T( P.FromString(dict["P"]), int.Parse(dict["V"] , System.Globalization.NumberStyles.HexNumber , CultureInfo.InvariantCulture ) ); } public static bool operator ==(T l, T r) { return l.Equals(r); } public static bool operator !=(T l, T r) { return !l.Equals(r); } public static T operator +(T o) { return o; } public static T operator -(T o) { return o.InverseElement; } public static T operator +(T l, T r) { return l.Add(r); } public static T operator -(T l, T r) { return l.Subtract(r); } public static T operator *(T l, int r) { return l.Times(r); } public static T operator *(int l, T r) { return r.Times(l); } public static implicit operator T(P o) { return new T(o, 0); } } }