├── .github └── FUNDING.yml ├── .gitignore ├── C5sdpC4.png ├── C7sdpC3.png ├── FastGoat.sln ├── FastGoat ├── AllGroupsOrder64.txt ├── AllSmallGroups120.txt ├── AllTransitivesGroups8.txt ├── Commons │ ├── Array2Tuple.cs │ ├── Array2Tuple.tt │ ├── DistributionExt.cs │ ├── EllipticExt.cs │ ├── EnumerableExt.cs │ ├── GlobalStopWatch.cs │ ├── GroupExt.cs │ ├── IntExt.cs │ ├── Lipsum.cs │ ├── Logger.cs │ ├── MatrixExt.cs │ ├── PadicExt.cs │ ├── PolynomExt.cs │ └── Tuple2Array.cs ├── DetailsGroupsOfOrder33to63.txt ├── DetailsGroupsUptoOrder32.txt ├── Examples │ ├── AbelianInvariantsFactors.cs │ ├── AbelianInvariantsFactorsPart2.cs │ ├── ActionProperties.cs │ ├── AlgebraicFactorization.cs │ ├── AlgebraicIntegerRelationLLL.cs │ ├── AlgebraicIntegerRelationPSLQ.cs │ ├── AllGroupsUptoOrder32.cs │ ├── AllGroupsUptoOrder64.cs │ ├── AllSubGroups.cs │ ├── BCHcodes.cs │ ├── BivariatePolynomialFactorization.cs │ ├── CardanFormula.cs │ ├── CayleyGraph.cs │ ├── CentralSeries.cs │ ├── CharacterTableExamples.cs │ ├── CharacterTableExamplesPart2.cs │ ├── CocyclesDFS.cs │ ├── Cohomology.cs │ ├── ConwayPolynoms.cs │ ├── CyclotomicPolynomials.cs │ ├── DefiningRelators.cs │ ├── DihedralAutomorphisms.cs │ ├── EllipticCurves.cs │ ├── EllipticCurvesPart2.cs │ ├── FiniteFields.cs │ ├── GL23SubGroups.cs │ ├── GLnK.cs │ ├── GLnp.cs │ ├── GaloisApplications.cs │ ├── GaloisApplicationsPart2.cs │ ├── GaloisTheory.cs │ ├── GroebnerBasis.cs │ ├── GroupAction.cs │ ├── GroupMatrixForm.cs │ ├── GroupMatrixFormPart2.cs │ ├── GroupNaming.cs │ ├── GroupOrder18.cs │ ├── GroupOrder21.cs │ ├── GroupOrder32C4C8.cs │ ├── HolomorphC7.cs │ ├── InvariantTheory.cs │ ├── LearningWithErrors.cs │ ├── MathieuGroup.cs │ ├── NilpotentGroups.cs │ ├── NonSplitExtension.cs │ ├── NonSplitExtensionPart2.cs │ ├── PSL2q.cs │ ├── PSLnp.cs │ ├── PolynomialFactorization.cs │ ├── PolynomialFactorizationPart2.cs │ ├── PolynomialOperations.cs │ ├── ReadMeCode.cs │ ├── ResolventTheory.cs │ ├── SylowTheorems.cs │ ├── SymbolicMatrix.cs │ ├── Symmetric6.cs │ ├── ToddCoxeter.cs │ └── UnitaryGroup.cs ├── FastGoat.csproj ├── Program.cs ├── Structures │ ├── CartesianProduct │ │ ├── GE.cs │ │ ├── GpEp.cs │ │ └── GpEp.tt │ ├── DisplayGroup.cs │ ├── GenericGroup │ │ ├── Automorphism.cs │ │ ├── AutomorphismGroup.cs │ │ ├── ConcreteGroup.cs │ │ ├── ConjugacyClasses.cs │ │ ├── Coset.cs │ │ ├── CosetType.cs │ │ ├── ExtensionGroup.cs │ │ ├── ExtensionGroupBase.cs │ │ ├── GroupSetEquality.cs │ │ ├── GroupWrapper.cs │ │ ├── Homomorphism.cs │ │ ├── IsomorphEquality.cs │ │ ├── MapElt.cs │ │ ├── MapGroupBase.cs │ │ ├── OpGroup.cs │ │ ├── Quotient.cs │ │ └── SemiDirectProduct.cs │ ├── Group.cs │ ├── Group.morphism.cs │ ├── Group.tools.cs │ ├── GroupException.cs │ ├── GroupType.cs │ ├── ICoset.cs │ ├── IElt.cs │ ├── IGmoduleNElt.cs │ ├── IGroup.cs │ ├── IMap.cs │ ├── IRingFieldVspaceElt.cs │ ├── Naming │ │ ├── ANameElt.cs │ │ ├── DirectProductOp.cs │ │ ├── ExtensionOp.cs │ │ ├── Leaf.cs │ │ ├── NamesTree.cs │ │ └── SemiDirectProductOp.cs │ ├── Ring.GrobnerBasis.cs │ ├── Ring.cs │ ├── Ring.matrix.cs │ ├── Subgroups │ │ ├── AllSubgroups.cs │ │ ├── GroupSubset.cs │ │ ├── Serie.cs │ │ ├── SerieType.cs │ │ ├── SubGroupsInfos.cs │ │ └── SubgroupConjugates.cs │ └── VecSpace │ │ ├── EPoly.cs │ │ ├── EPolynomial.cs │ │ ├── FracPoly.cs │ │ ├── GLnK.cs │ │ ├── Indeterminates.cs │ │ ├── KAut.cs │ │ ├── KAutGroup.cs │ │ ├── KMatrix.cs │ │ ├── KPoly.cs │ │ ├── Monom.cs │ │ ├── Polynomial.cs │ │ ├── PolynomialBasis.cs │ │ ├── SPoly.cs │ │ ├── Vec.cs │ │ └── Xi.cs └── UserGroup │ ├── Characters │ ├── AddCharacterState.cs │ ├── Character.cs │ ├── CharacterTable.cs │ └── CharacterTable.orth.cs │ ├── DatabaseSmallGroups │ └── IdGroup.cs │ ├── EllCurve │ ├── EC.cs │ ├── EC.schoof.cs │ ├── EllCoefs.cs │ ├── EllDB.cs │ ├── EllFracPoly.cs │ ├── EllGroup.cs │ ├── EllPoly.cs │ ├── EllPt.cs │ ├── IndTriVar.cs │ ├── TateAlgo.cs │ └── TriVar.cs │ ├── FG.character.cs │ ├── FG.cs │ ├── FG.ext.cs │ ├── FG.ring.cs │ ├── Floats │ ├── BigCplx.cs │ ├── BigReal.cs │ ├── Cplx.cs │ ├── Dble.cs │ ├── Dcml.cs │ └── PSLQM2.cs │ ├── GModuleN │ ├── AbelianDirectSum.cs │ ├── CrMap.cs │ ├── SysReduction.cs │ ├── SysSolution.cs │ ├── TestTwoCohomology.cs │ ├── ZNElt.cs │ └── ZNSolver.cs │ ├── Integers │ ├── Cn.cs │ ├── NumberTheory.cs │ ├── Rational.cs │ ├── Un.cs │ ├── Zn.cs │ ├── ZnBigInt.cs │ └── ZnInt.cs │ ├── LWE │ ├── NTTCipher.cs │ ├── NTTInfos.cs │ ├── RLWE.bgv.cs │ ├── RLWE.boot.cs │ ├── RLWE.cs │ ├── RLWE.ntt.cs │ ├── RLWECipher.cs │ ├── Regev.cs │ └── RegevCipher.cs │ ├── Matrix │ ├── GL.cs │ ├── GLnq.cs │ ├── Mat.cs │ └── MatFq.cs │ ├── Padic │ ├── Modulus.cs │ ├── PadicGAP.cs │ ├── PadicZealous.cs │ ├── Valuation.cs │ └── ZnBInt.cs │ ├── Perms │ ├── Perm.cs │ ├── Sn.cs │ └── Symm.cs │ ├── Polynoms │ ├── Cnf.cs │ ├── CnfBasis.cs │ ├── CyclotomicGroup.cs │ ├── ExternLibs.cs │ ├── Fq.cs │ ├── GFp.cs │ ├── IntFactorisation.algebraic.cs │ ├── IntFactorisation.bivariate.cs │ ├── IntFactorisation.cs │ └── IntFactorisation.rationals.cs │ └── Words │ ├── StringExt.cs │ ├── Tools │ ├── Circuit.cs │ ├── Circuit.partial.cs │ ├── Class.cs │ ├── Class.partial.cs │ ├── Gen.cs │ ├── Graph.cs │ ├── Graph.partial.cs │ └── Relator.cs │ ├── Word.cs │ ├── WordGroup.cs │ └── WordGroupBase.cs ├── LICENSE ├── README.md ├── Tests ├── AutomorphismUnitTest.cs ├── BigRealUnitTest.cs ├── ExamplesUnitTest.cs ├── GLnpUnitTest.cs ├── GaloisUnitTest.cs ├── GeneratorsUnitTest.cs ├── MorphismUnitTest.cs ├── PadicUnitTest.cs ├── PermutationUnitTest.cs ├── SemiDirectProdUnitTest.cs ├── SnUnitTest.cs ├── StaticExtUnittest.cs ├── Tests.csproj ├── ToddCoxeterUnitTest.cs ├── UserGroupUnitTest.cs ├── ZnCGroupUnitTest.cs ├── ZnQuotientUnitTest.cs └── ZnUnitTest.cs ├── docs ├── _config.yml ├── _layouts │ └── default.html ├── favicon.ico └── index.md └── global.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: ilyasabdourahim 2 | -------------------------------------------------------------------------------- /C5sdpC4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidevnn/FastGoat/619188c32e5c386270dc012e9f6559b33ad14b36/C5sdpC4.png -------------------------------------------------------------------------------- /C7sdpC3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidevnn/FastGoat/619188c32e5c386270dc012e9f6559b33ad14b36/C7sdpC3.png -------------------------------------------------------------------------------- /FastGoat.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30114.105 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastGoat", "FastGoat\FastGoat.csproj", "{449ECED4-4D12-4A6A-8205-69E5609C6C3B}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2483D5E8-E8ED-4479-8F09-DC38E613D439}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(SolutionProperties) = preSolution 16 | HideSolutionNode = FALSE 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {449ECED4-4D12-4A6A-8205-69E5609C6C3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {449ECED4-4D12-4A6A-8205-69E5609C6C3B}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {449ECED4-4D12-4A6A-8205-69E5609C6C3B}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {449ECED4-4D12-4A6A-8205-69E5609C6C3B}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {2483D5E8-E8ED-4479-8F09-DC38E613D439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {2483D5E8-E8ED-4479-8F09-DC38E613D439}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {2483D5E8-E8ED-4479-8F09-DC38E613D439}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {2483D5E8-E8ED-4479-8F09-DC38E613D439}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /FastGoat/Commons/Array2Tuple.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace FastGoat.Commons; 4 | 5 | public class Array2Tuple : IEquatable>, IEnumerable 6 | { 7 | private IEnumerable array { get; } 8 | 9 | public Array2Tuple(IEnumerable arr) 10 | { 11 | array = arr; 12 | } 13 | 14 | public T this[int index] => array.ElementAt(index); 15 | 16 | public void Deconstruct(out T a0, out T a1) 17 | { 18 | (a0, a1) = (this[0], this[1]); 19 | } 20 | 21 | public void Deconstruct(out T a0, out T a1, out T a2) 22 | { 23 | (a0, a1, a2) = (this[0], this[1], this[2]); 24 | } 25 | 26 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3) 27 | { 28 | (a0, a1, a2, a3) = (this[0], this[1], this[2], this[3]); 29 | } 30 | 31 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3, out T a4) 32 | { 33 | (a0, a1, a2, a3, a4) = (this[0], this[1], this[2], this[3], this[4]); 34 | } 35 | 36 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3, out T a4, out T a5) 37 | { 38 | (a0, a1, a2, a3, a4, a5) = (this[0], this[1], this[2], this[3], this[4], this[5]); 39 | } 40 | 41 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6) 42 | { 43 | (a0, a1, a2, a3, a4, a5, a6) = (this[0], this[1], this[2], this[3], this[4], this[5], this[6]); 44 | } 45 | 46 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6, out T a7) 47 | { 48 | (a0, a1, a2, a3, a4, a5, a6, a7) = (this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7]); 49 | } 50 | 51 | public void Deconstruct(out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6, out T a7, out T a8) 52 | { 53 | (a0, a1, a2, a3, a4, a5, a6, a7, a8) = (this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7], this[8]); 54 | } 55 | 56 | public override string ToString() 57 | { 58 | return $"({array.Glue(", ")})"; 59 | } 60 | 61 | public bool Equals(Array2Tuple? other) => other != null && other.array.SequenceEqual(array); 62 | 63 | public override int GetHashCode() => (array.Count(), typeof(T)).GetHashCode(); 64 | 65 | public IEnumerator GetEnumerator() => array.GetEnumerator(); 66 | 67 | IEnumerator IEnumerable.GetEnumerator() 68 | { 69 | return GetEnumerator(); 70 | } 71 | } -------------------------------------------------------------------------------- /FastGoat/Commons/Array2Tuple.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" #> 2 | <#@ output extension=".cs"#> 3 | <#@ assembly name="System.Core" #> 4 | <#@ import namespace="System.Collections.Generic" #> 5 | <#@ import namespace="System.Linq" #> 6 | <# 7 | string Glue(IEnumerable ts, string sep = "", string fmt = "{0}") 8 | { 9 | return string.Join(sep, ts.Select(t => string.Format(fmt, t))); 10 | } 11 | #> 12 | using System.Collections; 13 | 14 | namespace FastGoat.Commons; 15 | 16 | public class Array2Tuple : IEquatable>, IEnumerable 17 | { 18 | private IEnumerable array { get; } 19 | 20 | public Array2Tuple(IEnumerable arr) 21 | { 22 | array = arr; 23 | } 24 | 25 | public T this[int index] => array.ElementAt(index); 26 | <# 27 | for (int i = 2; i < 10; i++) 28 | { 29 | var ais = Enumerable.Range(0, i).Select(j => $"a{j}").ToArray(); 30 | var parms = Glue(ais, ", ", "out T {0}"); 31 | var lhs = Glue(ais, ", "); 32 | var rhs = Glue(Enumerable.Range(0, i), ", ", "this[{0}]"); 33 | #> 34 | 35 | public void Deconstruct(<#= parms #>) 36 | { 37 | (<#= lhs #>) = (<#= rhs #>); 38 | } 39 | <# 40 | } 41 | #> 42 | 43 | public override string ToString() 44 | { 45 | return $"({array.Glue(", ")})"; 46 | } 47 | 48 | public bool Equals(Array2Tuple? other) => other != null && other.array.SequenceEqual(array); 49 | 50 | public override int GetHashCode() => (array.Count(), typeof(T)).GetHashCode(); 51 | 52 | public IEnumerator GetEnumerator() => array.GetEnumerator(); 53 | 54 | IEnumerator IEnumerable.GetEnumerator() 55 | { 56 | return GetEnumerator(); 57 | } 58 | } -------------------------------------------------------------------------------- /FastGoat/Commons/GlobalStopWatch.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace FastGoat.Commons; 4 | 5 | /// 6 | /// A static class providing global stopwatch functionality 7 | /// 8 | public static class GlobalStopWatch 9 | { 10 | // Stopwatch to be used by all functions in the class 11 | static Stopwatch sw { get; } 12 | 13 | // Stack to keep track of individual laps 14 | private static Stack Lapse { get; } 15 | 16 | // Initializes the stopwatch and lap stack 17 | static GlobalStopWatch() 18 | { 19 | sw = Stopwatch.StartNew(); 20 | Lapse = new(); 21 | } 22 | 23 | /// 24 | /// Restarts the stopwatch and clears the lap stack 25 | /// 26 | public static void Restart() 27 | { 28 | sw.Restart(); 29 | Lapse.Clear(); 30 | } 31 | 32 | /// 33 | /// Records a lap on the stopwatch 34 | /// 35 | public static void AddLap() 36 | { 37 | Lapse.Push(sw.ElapsedMilliseconds); 38 | } 39 | 40 | /// 41 | /// Stops the stopwatch 42 | /// 43 | public static void Stop() => sw.Stop(); 44 | 45 | /// 46 | /// Outputs the elapsed time since the last lap or start 47 | /// 48 | /// Label to be output before the time 49 | public static void Show(string label = "") 50 | { 51 | var start = Lapse.Count == 0 ? 0 : Lapse.Pop(); 52 | var time = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds - start); 53 | if (time.Hours > 0) 54 | Console.WriteLine($"# {label} Time:{time.Hours}h{time.Minutes}m"); 55 | else if (time.Minutes > 0) 56 | Console.WriteLine($"# {label} Time:{time.Minutes}m{time.Seconds}s"); 57 | else if (time.Seconds > 0) 58 | Console.WriteLine($"# {label} Time:{time.Seconds}.{time.Milliseconds:000}s"); 59 | else 60 | Console.WriteLine($"# {label} Time:{sw.ElapsedMilliseconds - start}ms"); 61 | } 62 | 63 | /// 64 | /// Runs an action and returns the elapsed time 65 | /// 66 | /// Label to be output before and after the action 67 | /// Action to be executed and timed 68 | /// Flag to indicate whether to output the label or not 69 | /// The elapsed time in milliseconds 70 | public static long Time(string label, Action action, bool lbl = true) 71 | { 72 | if (lbl) 73 | Console.WriteLine($"# {label} Start"); 74 | 75 | sw.Restart(); 76 | action(); 77 | sw.Stop(); 78 | 79 | if (lbl) 80 | Console.WriteLine($"# {label} Time:{sw.ElapsedMilliseconds} ms"); 81 | 82 | return sw.ElapsedMilliseconds; 83 | } 84 | 85 | /// 86 | /// Runs an action multiple times and outputs the average and deviation 87 | /// 88 | /// Number of times to run the action 89 | /// Label to be output before and after the action 90 | /// Action to be executed and timed 91 | public static void Bench(int nb, string label, Action action) 92 | { 93 | if (nb < 1) 94 | throw new(); 95 | 96 | var list = new List(); 97 | for (int i = 0; i < nb; i++) 98 | list.Add(Time(label, action, false)); 99 | 100 | var avg = list.Average(); 101 | var dev = Double.Sqrt(list.Select(t => Double.Pow(t - avg, 2)).Average()); 102 | Console.WriteLine($"# {label} Avg Time:{(long)avg} ms Dev:{dev:F}"); 103 | } 104 | 105 | // Counter for infinite loop breaker 106 | private static int ct = 0; 107 | 108 | /// 109 | /// Resets the infinite loop breaker counter 110 | /// 111 | public static void InfiniteLoopBreakerReset() => ct = 0; 112 | 113 | /// 114 | /// Throws an exception if a specified number of iterations have been exceeded 115 | /// 116 | /// maximum number of iterations before the loop is considered infinite 117 | /// custom error message displayed in case the loop is broken (optional) 118 | public static void InfiniteLoopBreaker(int n, string msg = "") 119 | { 120 | ++ct; 121 | if (ct > n) 122 | throw new ArgumentException($"################## Infinite Loop breaker ### {msg}"); 123 | } 124 | } -------------------------------------------------------------------------------- /FastGoat/Commons/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Commons; 2 | 3 | public enum LogLevel 4 | { 5 | Off, 6 | Level1, 7 | Level2 8 | } 9 | 10 | public static class Logger 11 | { 12 | public static LogLevel Level { get; set; } = LogLevel.Off; 13 | 14 | public static LogLevel SetOff() 15 | { 16 | var lvl = Level; 17 | Level = LogLevel.Off; 18 | return lvl; 19 | } 20 | } -------------------------------------------------------------------------------- /FastGoat/Commons/PadicExt.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace FastGoat.Commons; 4 | 5 | /// 6 | /// Extension class for p-adic integers. 7 | /// 8 | public static class PadicExt 9 | { 10 | /// 11 | /// Calculates the valuation of a p-adic integer. 12 | /// 13 | /// The prime p. 14 | /// The p-adic integer to calculate the valuation for. 15 | /// A tuple containing the valuation and the remaining p-adic. 16 | public static (int val, BigInteger nb) GetValuation(int p, BigInteger n) 17 | { 18 | if (n.IsZero) 19 | return (0, 0); 20 | 21 | var n0 = n; 22 | var v = 0; 23 | while (!n0.IsOne) 24 | { 25 | var (q, r) = BigInteger.DivRem(n0, p); 26 | if (r != 0) 27 | break; 28 | 29 | ++v; 30 | n0 = q; 31 | } 32 | 33 | return (v, n0); 34 | } 35 | 36 | /// 37 | /// Adds a given valuation to a p-adic integer. 38 | /// 39 | /// The prime p. 40 | /// The p-adic integer to add the value to. 41 | /// The valuation to add. 42 | /// A tuple containing the sum of the new valuation and the remaining p-adic integer. 43 | public static (int val, BigInteger nb) AddValuation(int p, BigInteger n, int val) 44 | { 45 | var (v0, n0) = GetValuation(p, n); 46 | return (v0 + val, n0); 47 | } 48 | } -------------------------------------------------------------------------------- /FastGoat/Commons/Tuple2Array.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace FastGoat.Commons; 4 | 5 | /// 6 | /// Extension class for implicit conversion of integers tuples to integers array. 7 | /// 8 | public class Tuple2Array 9 | { 10 | /// 11 | /// Gets or sets the Table property. 12 | /// 13 | public int[] Table { get; private set; } 14 | 15 | /// 16 | /// Creates a new instance of Tuple2Array with the given parameters. 17 | /// 18 | /// An array of integers representing the elements in the tuple. 19 | public Tuple2Array(params int[] table) 20 | { 21 | Table = table.ToArray(); 22 | } 23 | 24 | /// 25 | /// Returns a string representation of the Table object. 26 | /// 27 | /// A string containing the elements of the Table object, separated by spaces. 28 | public override string ToString() => $"[{Table.Glue(" ")}]"; 29 | 30 | /// 31 | /// Implicitly converts a ValueType to a Tuple2Array. 32 | /// 33 | /// The ValueType can be an integer or a tuple of integers 34 | /// The ValueType to convert. 35 | /// A new Tuple2Array. 36 | public static implicit operator Tuple2Array(ValueType v) 37 | { 38 | if (v is int v1) 39 | return new(v1); 40 | 41 | if (v is ITuple vx && Enumerable.Range(0, vx.Length).All(i => vx[i] is int)) 42 | return new(Enumerable.Range(0, vx.Length).Select(i => (int)(vx[i] ?? 0)).ToArray()); 43 | 44 | return new(); 45 | } 46 | 47 | /// 48 | /// Converts a ValueType to a Tuple2Array. 49 | /// 50 | /// The ValueType can be an integer or a tuple of integers or a tuple of tuples of integer 51 | /// The ValueType to convert. 52 | /// A new array of Tuple2Array. 53 | public static Tuple2Array[] ComplexTuples(ValueType v) 54 | { 55 | var c0 = (Tuple2Array)v; 56 | if (c0.Table.Length > 0) 57 | return new[] { c0 }; 58 | 59 | if (v is ITuple t) 60 | { 61 | var tuples = Enumerable.Range(0, t.Length) 62 | .Select(i => t[i] as ValueType ?? new Tuple2Array()) 63 | .Where(e => e.Table.Length > 0) 64 | .ToArray(); 65 | 66 | return tuples; 67 | } 68 | 69 | return Array.Empty(); 70 | } 71 | } -------------------------------------------------------------------------------- /FastGoat/Examples/AbelianInvariantsFactors.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.CartesianProduct; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.Structures.GenericGroup; 5 | using FastGoat.UserGroup.Integers; 6 | 7 | namespace FastGoat.Examples; 8 | 9 | public static class AbelianInvariantsFactors 10 | { 11 | static void Reduce(ConcreteGroup g, Stack facts) where T : struct, IElt 12 | { 13 | if (g.GroupType == GroupType.NonAbelianGroup) 14 | throw new Exception("Only Abelian Group"); 15 | 16 | if (g.Count() == 1) 17 | return; 18 | 19 | var g0 = g; 20 | var p = g0.ElementsOrders.OrderByDescending(e => e.Value).ThenBy(e => e.Key).First(); 21 | var h = Group.Generate($"C{p.Value}", g0, p.Key); 22 | var g1 = g0.Over(h); 23 | facts.Push(p.Value); 24 | Reduce(g1, facts); 25 | } 26 | 27 | public static Stack Reduce(ConcreteGroup g) where T : struct, IElt 28 | { 29 | Stack facts = new Stack(); 30 | Reduce(g, facts); 31 | return facts; 32 | } 33 | 34 | public static void InvariantFactors294() 35 | { 36 | var c14 = new Cn(14); 37 | var c21 = new Cn(21); 38 | 39 | var bg = Product.Group(c14, c21); 40 | var g = Group.Create(bg.Name, bg); 41 | var decomposition = Reduce(g); 42 | Console.WriteLine("{0} ~ {1}", g, decomposition.Glue(" x ", "C{0}")); 43 | } 44 | 45 | public static void InvariantFactors600() 46 | { 47 | var c20 = new Cn(20); 48 | var c30 = new Cn(30); 49 | 50 | var bg = Product.Group(c20, c30); 51 | var g = Group.Create(bg.Name, bg); 52 | var decomposition = Reduce(g); 53 | Console.WriteLine("{0} ~ {1}", g, decomposition.Glue(" x ", "C{0}")); 54 | } 55 | 56 | public static void InvariantFactors4320() 57 | { 58 | var c8 = new Cn(8); 59 | var c18 = new Cn(18); 60 | var c30 = new Cn(30); 61 | 62 | var bg = Product.Group(c8, c18, c30); 63 | var g = Group.Create(bg.Name, bg); 64 | var decomposition = Reduce(g); 65 | Console.WriteLine("{0} ~ {1}", g, decomposition.Glue(" x ", "C{0}")); 66 | } 67 | 68 | public static void UnIsomorphisms() 69 | { 70 | for (int i = 3; i < 120; ++i) 71 | { 72 | var un = new Un(i); 73 | var dec = Reduce(un); 74 | Console.WriteLine("U{0,-3} ~ {1}", i, dec.Glue(" x ", "C{0}")); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /FastGoat/Examples/CayleyGraph.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.UserGroup; 4 | using FastGoat.UserGroup.Words.Tools; 5 | 6 | namespace FastGoat.Examples; 7 | 8 | public static class CayleyGraph 9 | { 10 | public static void ExamplesCayleyGraph() 11 | { 12 | DisplayGroup.HeadElementsCayleyGraph(FG.AbelianPerm(5)); 13 | DisplayGroup.HeadElementsCayleyGraph(FG.Symmetric(3)); 14 | DisplayGroup.HeadElementsCayleyGraph(FG.Dihedral(4)); 15 | DisplayGroup.HeadElementsCayleyGraph(FG.QuaternionWg(8)); 16 | DisplayGroup.HeadElementsCayleyGraph(FG.MetaCyclicSdpWg(7, 3, 2)); 17 | } 18 | 19 | public static void GroupsUptoOrder12() 20 | { 21 | foreach (var g in 16.Range(1).SelectMany(o => FG.AllGroupsOfOrder(o))) 22 | DisplayGroup.HeadElementsCayleyGraph(g); 23 | } 24 | 25 | public static void Q8ThreeGenerators() 26 | { 27 | var q8a = FG.DiCyclicThreeGens(2); 28 | 29 | var (a, b, c) = q8a.GetGenerators().Deconstruct(); 30 | Console.WriteLine($"{q8a}:{q8a.Definition}"); 31 | Console.WriteLine($"b2 = {q8a.Times(b, 2)} and c2 = {q8a.Times(c, 2)}"); 32 | Console.WriteLine($"ab = {q8a.Op(a, b)} and (ba)-1 = {q8a.Invert(q8a.Op(b, a))}"); 33 | Console.WriteLine($"bc = {q8a.Op(b, c)} and (cb)-1 = {q8a.Invert(q8a.Op(c, b))}"); 34 | Console.WriteLine($"ca = {q8a.Op(c, a)} and (ac)-1 = {q8a.Invert(q8a.Op(a, c))}"); 35 | Console.WriteLine(); 36 | 37 | DisplayGroup.HeadElementsCayleyGraph(q8a); 38 | } 39 | 40 | public static void A4ThreeGenerators() 41 | { 42 | var a4 = FG.Alternate(4); 43 | DisplayGroup.HeadElementsCayleyGraph(a4); 44 | 45 | var gens = a4.Where(e => a4.ElementsOrders[e] == 2).Take(2) 46 | .Append(a4.First(e => a4.ElementsOrders[e] == 3)) 47 | .ToArray(); 48 | 49 | DisplayGroup.HeadElementsCayleyGraph(a4, gens: gens); 50 | 51 | var a4wg = FG.WordGroup("A4", Graph.DefiningRelatorsOfGroup(a4, gens)); 52 | Console.WriteLine($"{a4wg}:{a4wg.Definition}"); 53 | DisplayGroup.HeadElementsCayleyGraph(a4wg); 54 | } 55 | 56 | public static void S4CayleyGraph1() 57 | { 58 | var s4 = FG.Symmetric(4); 59 | DisplayGroup.HeadElementsCayleyGraph(s4); 60 | 61 | var (c2, c4) = (s4.First(e => s4.ElementsOrders[e] == 2), s4.First(e => s4.ElementsOrders[e] == 4)); 62 | var s4wg = FG.WordGroup("S4", Graph.DefiningRelatorsOfGroup(s4, [c2, c4])); 63 | Console.WriteLine($"{s4wg}:{s4wg.Definition}"); 64 | DisplayGroup.HeadElementsCayleyGraph(s4wg); 65 | } 66 | 67 | public static void S4CayleyGraph2() 68 | { 69 | var s4 = FG.Symmetric(4); 70 | DisplayGroup.HeadElementsCayleyGraph(s4); 71 | 72 | var (c3, c4) = (s4.First(e => s4.ElementsOrders[e] == 3), s4.First(e => s4.ElementsOrders[e] == 4)); 73 | var s4wg = FG.WordGroup("S4", Graph.DefiningRelatorsOfGroup(s4, [c3, c4])); 74 | Console.WriteLine($"{s4wg}:{s4wg.Definition}"); 75 | DisplayGroup.HeadElementsCayleyGraph(s4wg); 76 | } 77 | } -------------------------------------------------------------------------------- /FastGoat/Examples/CharacterTableExamplesPart2.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.Structures.CartesianProduct; 4 | using FastGoat.Structures.GenericGroup; 5 | using FastGoat.UserGroup; 6 | using FastGoat.UserGroup.Characters; 7 | using FastGoat.UserGroup.Polynoms; 8 | 9 | namespace FastGoat.Examples; 10 | 11 | public static class CharacterTableExamplesPart2 12 | { 13 | static CharacterTable TensorTable(CharacterTable ctG, ConcreteGroup H, ConcreteGroup K) 14 | where T : struct, IElt 15 | { 16 | if (ctG.TableComplete) 17 | return ctG; 18 | 19 | var G = ctG.Gr; 20 | var ctH = FG.CharacterTable(H); 21 | var ctK = FG.CharacterTable(K); 22 | if (H.Name == "SL(2,3)") 23 | ctH.SolveOrthogonality(); 24 | if (K.Name == "SL(2,3)") 25 | ctK.SolveOrthogonality(); 26 | 27 | var keys = H.Grid2D(K).Select(e => (h: e.t1, k: e.t2, hk: ctG.Classes.GetRepresentative(G.Op(e.t1, e.t2)))) 28 | .DistinctBy(e => e.hk) 29 | .ToArray(); 30 | 31 | foreach (var (chi1, chi2) in ctH.AllCharacters.Grid2D(ctK.AllCharacters)) 32 | { 33 | var map = keys.ToDictionary(e => e.hk, e => (Cnf?)(chi1[e.h]!.Value * chi2[e.k]!.Value)); 34 | var state = ctG.AddCharacter(new(ctG.Classes, map)); 35 | if (state == AddCharacterState.TableFull) 36 | break; 37 | } 38 | 39 | if (Logger.Level != LogLevel.Off) 40 | { 41 | ctH.DisplayCells(); 42 | ctK.DisplayCells(); 43 | } 44 | 45 | return ctG; 46 | } 47 | 48 | static void TensorTable(ConcreteGroup g) where T : struct, IElt 49 | { 50 | var gSubgrs = g.AllSubgroups(); 51 | gSubgrs.Naming(); 52 | var dirProd = gSubgrs.DecomposeProducts(gSubgrs.ProperNonTrivialNormalSubgroups()) 53 | .Where(e => e.isDirectProduct).Take(1).ToArray(); 54 | if (dirProd.Length == 0) 55 | return; 56 | 57 | var (H, K) = (dirProd[0].lhs.Representative, dirProd[0].rhs.Representative); 58 | 59 | Console.WriteLine($"#### {g.Name} = {H.Name} x {K.Name} ####"); 60 | var ctG = FG.CharacterTableEmpty(g); 61 | ctG = TensorTable(ctG, H, K); 62 | ctG.DisplayCells(); 63 | 64 | var ctG2 = FG.CharacterTableEmpty(g); 65 | ctG2.DerivedSubGroupLift(); 66 | ctG2.InductionFromStabilizers(); 67 | ctG2.InductionFromSubGroups(gSubgrs); 68 | ctG2.OrderCharacters(); 69 | 70 | if (!ctG.AllCharacters.Zip(ctG2.AllCharacters).All(e=> e.First.Equals(e.Second))) 71 | { 72 | Console.WriteLine("----------------------------------------------------------------------------------------------"); 73 | ctG2.DisplayCells(); 74 | 75 | Console.WriteLine("#### Error"); 76 | Console.Beep(); 77 | } 78 | 79 | Console.WriteLine($"END {g.ShortName}"); 80 | 81 | Console.WriteLine(); 82 | } 83 | 84 | public static void Example1() 85 | { 86 | Logger.Level = LogLevel.Level1; 87 | TensorTable(FG.Abelian(2, 3)); 88 | TensorTable(Product.Generate(FG.AbelianPerm(3), FG.Dihedral(4))); 89 | } 90 | 91 | public static void Example2() 92 | { 93 | // Logger.Level = LogLevel.Level1; 94 | foreach (var g in FG.AllGroupsOfOrder(1, 48).Where(g => g.GroupType == GroupType.NonAbelianGroup)) 95 | TensorTable(g); 96 | } 97 | } -------------------------------------------------------------------------------- /FastGoat/Examples/CyclotomicPolynomials.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.UserGroup; 4 | using FastGoat.UserGroup.Integers; 5 | using FastGoat.UserGroup.Polynoms; 6 | 7 | namespace FastGoat.Examples; 8 | 9 | public static class CyclotomicPolynomials 10 | { 11 | public static void First30CyclotomicsPolynomials() 12 | { 13 | for (int i = 1; i <= 30; i++) 14 | { 15 | Console.WriteLine($"Phi({i}) = {FG.CyclotomicPolynomial(i)}"); 16 | } 17 | } 18 | 19 | public static void First20NthRootQ() 20 | { 21 | for (int n = 2; n <= 22; n++) 22 | { 23 | var unq = new NthRootQ(n); 24 | DisplayGroup.HeadElements(unq); 25 | DisplayGroup.AreIsomorphics(unq, new Cn(n)); 26 | Console.WriteLine(); 27 | } 28 | } 29 | 30 | public static void First20NthRootF8() 31 | { 32 | for (int n = 3; n <= 22; n++) 33 | { 34 | if (IntExt.Gcd(n, 2) != 1) 35 | continue; 36 | 37 | var unq = new NthRootFq(n, 8); 38 | DisplayGroup.HeadElements(unq); 39 | DisplayGroup.AreIsomorphics(unq, new Cn(n)); 40 | var primElt = unq.PrimitivesRoots().First(); 41 | Console.WriteLine($"{unq} ~ F8({primElt}) ~ F2({primElt.KOne.X})({primElt})"); 42 | Console.WriteLine($" with {primElt.F} = 0 in {unq}"); 43 | Console.WriteLine($" and {primElt.KOne.F} = 0 in F8"); 44 | Console.WriteLine(); 45 | } 46 | } 47 | 48 | public static void First20NthRootF9() 49 | { 50 | for (int n = 2; n <= 22; n++) 51 | { 52 | if (IntExt.Gcd(n, 3) != 1) 53 | continue; 54 | 55 | var unq = new NthRootFq(n, 9); 56 | DisplayGroup.HeadElements(unq); 57 | DisplayGroup.AreIsomorphics(unq, new Cn(n)); 58 | var primElt = unq.PrimitivesRoots().First(); 59 | Console.WriteLine($"{unq} ~ F9({primElt}) ~ F3({primElt.KOne.X})({primElt})"); 60 | Console.WriteLine($" with {primElt.F} = 0 in {unq}"); 61 | Console.WriteLine($" and {primElt.KOne.F} = 0 in F9"); 62 | Console.WriteLine(); 63 | } 64 | } 65 | 66 | static void Fpm_Iso_FqZ(int p, int n, int d) 67 | { 68 | var m = n * d; 69 | var q1 = p.Pow(n); 70 | var q2 = p.Pow(m); 71 | var fq1 = Group.MulGroup($"F{q1}", FG.FqX(q1, 'α')); 72 | var fq2 = Group.MulGroup($"F{q2}", FG.FqX(q2, 'ζ')); 73 | var alpha = fq1.GetGenerators().First(); 74 | var Z = FG.KPoly('ζ', alpha); 75 | var zeta = fq2.GetGenerators().First().F; 76 | var minPol = IntFactorisation.Firr(zeta.Substitute(Z), alpha).First(); 77 | var fq3 = Group.MulGroup($"F{q1}({zeta.x})", FG.EPoly(minPol, 'y')); 78 | 79 | DisplayGroup.AreIsomorphics(fq2, fq3); 80 | Console.WriteLine($" with {minPol} = 0 in {fq3}"); 81 | Console.WriteLine(); 82 | } 83 | 84 | // GF(p^nd) ~ GF(p^n)(ζ) 85 | public static void Examples_Fpm_Iso_FpnZ() 86 | { 87 | Fpm_Iso_FqZ(p: 2, n: 2, d: 3); // F64 ~ F4(ζ) 88 | Fpm_Iso_FqZ(p: 2, n: 3, d: 2); // F64 ~ F8(ζ) 89 | Fpm_Iso_FqZ(p: 2, n: 2, d: 4); // F256 ~ F4(ζ) 90 | Fpm_Iso_FqZ(p: 2, n: 4, d: 2); // F256 ~ F16(ζ) 91 | Fpm_Iso_FqZ(p: 3, n: 2, d: 3); // F729 ~ F9(ζ) 92 | Fpm_Iso_FqZ(p: 3, n: 3, d: 2); // F729 ~ F27(ζ) 93 | } 94 | } -------------------------------------------------------------------------------- /FastGoat/Examples/DihedralAutomorphisms.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.Structures.GenericGroup; 4 | using FastGoat.UserGroup.Integers; 5 | using FastGoat.UserGroup.Perms; 6 | 7 | namespace FastGoat.Examples; 8 | 9 | public static class DihedralAutomorphisms 10 | { 11 | static ConcreteGroup DnPerm(int n = 16) 12 | { 13 | int m = (n % 2) == 0 ? 1 : 2; 14 | var sn = new Sn(n); 15 | var an = Enumerable.Range(1, n).ToArray(); 16 | var a2 = Enumerable.Range(m, n / 2).Select(i => (Tuple2Array)(i, n + m - i)).ToArray(); 17 | var cn = sn.Cycle(an); 18 | var c2 = sn.ComposesCycles(a2); 19 | var d2n = Group.Generate("D2n", sn, c2, cn); 20 | return d2n; 21 | } 22 | 23 | static SemiDirectProduct DnSdp(int n = 16) 24 | { 25 | var cn = new Cn(n); 26 | var c2 = new Cn(2); 27 | var un = new Un(n); 28 | var theta = new Dictionary>() 29 | { 30 | [c2[0]] = un.Neutral(), 31 | [c2[1]] = un[(cn[1], cn[n - 1])] 32 | }; 33 | 34 | var homTheta = Group.Hom(c2, theta); 35 | var d2n = Group.SemiDirectProd("D2n", cn, homTheta, c2); 36 | return d2n; 37 | } 38 | 39 | public static void Dn() 40 | { 41 | int n = 3; 42 | var d2n = DnSdp(n); 43 | var d2n2 = DnPerm(n); 44 | DisplayGroup.HeadSdp(d2n); 45 | DisplayGroup.Head(d2n2); 46 | Console.WriteLine("IsIsomorphic : {0}", d2n2.IsIsomorphicTo(d2n)); 47 | } 48 | 49 | public static void AutDn() 50 | { 51 | for (int n = 6; n <= 32; n += 2) 52 | { 53 | var d2n = DnSdp(n / 2); 54 | var autD2N = Group.AllAutomorphisms(d2n); 55 | 56 | var a = d2n[1, 0]; 57 | var b = d2n[0, 1]; 58 | var autH = autD2N.Where(aut => aut[a].Equals(a)).ToArray(); 59 | var autK = autD2N.Where(aut => aut[b].Equals(b)).ToArray(); 60 | 61 | var phi = new Un(n / 2).Count(); 62 | Console.WriteLine("|Aut(D{0})| = {1}; phi({2}) = {3}", n, autD2N.Count, n / 2, phi); 63 | Console.WriteLine($"a[{d2n.ElementsOrders[a]}]={a} b[{d2n.ElementsOrders[b]}]={b}"); 64 | Console.WriteLine("|y in Aut(D{0}), y(a)=a| = {1,-3}; |y in Aut(D{0}), y(b) = b| = {2,-3}", n, autH.Count(), 65 | autK.Count()); 66 | Console.WriteLine(); 67 | } 68 | 69 | // gap> for i in [2..16] do 70 | // > dn:=DihedralGroup(2*i); 71 | // > Print("Nb Aut(D", 2*i, ") = ", Size(AllAutomorphisms(dn)),"\n"); 72 | // > od; 73 | // Nb Aut(D4) = 6 74 | // Nb Aut(D6) = 6 75 | // Nb Aut(D8) = 8 76 | // Nb Aut(D10) = 20 77 | // Nb Aut(D12) = 12 78 | // Nb Aut(D14) = 42 79 | // Nb Aut(D16) = 32 80 | // Nb Aut(D18) = 54 81 | // Nb Aut(D20) = 40 82 | // Nb Aut(D22) = 110 83 | // Nb Aut(D24) = 48 84 | // Nb Aut(D26) = 156 85 | // Nb Aut(D28) = 84 86 | // Nb Aut(D30) = 120 87 | // Nb Aut(D32) = 128 88 | } 89 | 90 | public static void AutDnPerm() 91 | { 92 | for (int n = 6; n <= 32; n += 2) 93 | { 94 | var d2n = DnPerm(n / 2); 95 | var autD2N = Group.AllAutomorphisms(d2n); 96 | 97 | var gens = d2n.GetGenerators().ToArray(); 98 | var a = gens.First(e => d2n.ElementsOrders[e] == n / 2); 99 | var b = gens.First(e => d2n.ElementsOrders[e] == 2); 100 | var autH = autD2N.Where(aut => aut[a].Equals(a)).ToArray(); 101 | var autK = autD2N.Where(aut => aut[b].Equals(b)).ToArray(); 102 | 103 | var phi = new Un(n / 2).Count(); 104 | Console.WriteLine("|Aut(D{0})| = {1}; phi({2}) = {3}", n, autD2N.Count, n / 2, phi); 105 | Console.WriteLine($"a[{d2n.ElementsOrders[a]}]={a} b[{d2n.ElementsOrders[b]}]={b}"); 106 | Console.WriteLine("|y in Aut(D{0}), y(a)=a| = {1,-3}; |y in Aut(D{0}), y(b) = b| = {2,-3}", n, autH.Count(), 107 | autK.Count()); 108 | Console.WriteLine(); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /FastGoat/Examples/GLnK.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.UserGroup; 3 | using FastGoat.UserGroup.Integers; 4 | 5 | namespace FastGoat.Examples; 6 | 7 | public static class GLnK 8 | { 9 | public static void ExampleDihedralInReal() 10 | { 11 | var gl = FG.GLnK($"R", 2, Rational.KZero()); 12 | 13 | var m0 = gl[0, 1, -1, 0]; 14 | var m1 = gl[0, 1, 1, 0]; 15 | 16 | var g0 = Group.Generate("R(π/2)", gl, m0); 17 | DisplayGroup.HeadElements(g0); 18 | var g1 = Group.Generate("R(y=x)", gl, m1); 19 | DisplayGroup.HeadElements(g1); 20 | 21 | var g2 = Group.Generate("D8a", gl, m0, m1); 22 | DisplayGroup.HeadElements(g2); 23 | 24 | DisplayGroup.AreIsomorphics(g2, FG.Dihedral(4)); 25 | } 26 | 27 | public static void ExampleRotation1() 28 | { 29 | var x = FG.QPoly(); 30 | var a = FG.NumberFieldQ(x.Pow(2) - 2, "√2"); 31 | var gl = FG.GLnK($"Q({a})", 2, a); 32 | 33 | var m0 = gl[a / 2, a / 2, -a / 2, a / 2]; 34 | 35 | var c8 = Group.Generate("R(π/4)", gl, m0); 36 | DisplayGroup.HeadElements(c8); 37 | 38 | DisplayGroup.AreIsomorphics(c8, new Cn(8)); 39 | } 40 | 41 | public static void ExampleRotation2() 42 | { 43 | var x = FG.QPoly(); 44 | var (a, b) = FG.NumberFieldQ((x.Pow(2) - 2, "√2"), (x.Pow(2) - 3, "√3")); 45 | var gl = FG.GLnK($"Q({a},{b})", 2, a); 46 | 47 | var r1 = b.One / 2; 48 | var m0 = gl[a / 2, a / 2, -a / 2, a / 2]; 49 | var m1 = gl[r1, b / 2, -b / 2, r1]; 50 | 51 | var g0 = Group.Generate("R(π/3)", gl, m1); 52 | DisplayGroup.HeadElements(g0); 53 | var g1 = Group.Generate("R(π/12)", gl, m0, m1); 54 | DisplayGroup.HeadElements(g1); 55 | 56 | DisplayGroup.AreIsomorphics(g1, new Cn(24)); 57 | } 58 | 59 | public static void ExampleDihedralComplex() 60 | { 61 | var x = FG.QPoly(); 62 | var i = FG.NumberFieldQ(x.Pow(2) + 1, "i"); 63 | var gl = FG.GLnK($"Q({i})", 2, i); 64 | 65 | var m0 = gl[i, 0, 0, -i]; 66 | var m1 = gl[0, 1, 1, 0]; 67 | 68 | var g0 = Group.Generate("C4", gl, m0); 69 | DisplayGroup.HeadElements(g0); 70 | 71 | var g1 = Group.Generate("D8a", gl, m0, m1); 72 | DisplayGroup.HeadElements(g1); 73 | 74 | DisplayGroup.AreIsomorphics(g1, FG.Dihedral(4)); 75 | } 76 | 77 | public static void ExampleQuaternionComplex() 78 | { 79 | var x = FG.QPoly(); 80 | var i = FG.NumberFieldQ(x.Pow(2) + 1, "i"); 81 | var gl = FG.GLnK($"Q({i})", 2, i); 82 | 83 | var m0 = gl[i, 0, 0, -i]; 84 | var m1 = gl[0, 1, -1, 0]; 85 | 86 | var g1 = Group.Generate("Q8a", gl, m0, m1); 87 | DisplayGroup.HeadElements(g1); 88 | 89 | DisplayGroup.AreIsomorphics(g1, FG.Quaternion(8)); 90 | } 91 | 92 | public static void ExampleDicyclic4() 93 | { 94 | var x = FG.QPoly(); 95 | var (a, i) = FG.NumberFieldQ((x.Pow(2) - 2, "√2"), (x.Pow(2) + 1, "i")); 96 | var gl = FG.GLnK($"Q({i},{a})", 2, a); 97 | 98 | var m0 = gl[a / 2, a / 2, -a / 2, a / 2]; 99 | var m1 = gl[i, 0, 0, -i]; 100 | var m2 = gl[0, 1, -1, 0]; 101 | 102 | var g0 = Group.Generate("C8", gl, m0); 103 | DisplayGroup.HeadElements(g0); 104 | var g1 = Group.Generate("Q8", gl, m1, m2); 105 | DisplayGroup.HeadElements(g1); 106 | var g2 = Group.Generate("Dic4a", gl, m0, m1, m2); 107 | DisplayGroup.HeadElements(g2); 108 | 109 | DisplayGroup.AreIsomorphics(g2, FG.DiCyclic(4)); 110 | } 111 | 112 | public static void ExampleSemiDirectProd() 113 | { 114 | var x = FG.QPoly(); 115 | var (a, i) = FG.NumberFieldQ((x.Pow(2) - 3, "√3"), (x.Pow(2) + 1, "i")); 116 | var gl = FG.GLnK($"Q({i},{a})", 2, a); 117 | 118 | var m0 = gl[(1 + i * a) / 2, 0, 0, (1 - i * a) / 2]; 119 | var m1 = gl[i, 0, 0, -i]; 120 | var m2 = gl[0, 1, -1, 0]; 121 | 122 | var g0 = Group.Generate("C6", gl, m0); 123 | DisplayGroup.HeadElements(g0); 124 | var g1 = Group.Generate("Q8", gl, m1, m2); 125 | DisplayGroup.HeadElements(g1); 126 | var g2 = Group.Generate("G24", gl, m0, m1, m2); 127 | DisplayGroup.HeadElements(g2); 128 | 129 | var sdp = Group.SemiDirectProd(new Cn(3), FG.Quaternion(8)); 130 | DisplayGroup.HeadOrders(g2); 131 | DisplayGroup.HeadSdpOrders(sdp); 132 | DisplayGroup.AreIsomorphics(g2, sdp); 133 | } 134 | } -------------------------------------------------------------------------------- /FastGoat/Examples/GLnp.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.UserGroup.Matrix; 3 | using FastGoat.UserGroup.Perms; 4 | using FastGoat.UserGroup.Words; 5 | 6 | namespace FastGoat.Examples; 7 | 8 | public static class GLnp 9 | { 10 | public static void Minimal() 11 | { 12 | { 13 | var gl = new GL(2, 3); 14 | var a = gl[2, 0, 0, 1]; 15 | var b = gl[2, 1, 2, 0]; 16 | 17 | var g1 = Group.Generate(gl, a, b); 18 | DisplayGroup.HeadElements(g1); // 48 elements 19 | } 20 | 21 | { 22 | var gl = new GL(2, 3); 23 | var a = gl[1, 1, 0, 1]; 24 | var b = gl[0, 1, 2, 0]; 25 | 26 | var g1 = Group.Generate(gl, a, b); 27 | DisplayGroup.Head(g1); // 24 elements 28 | } 29 | 30 | { 31 | var gl = new GL(2, 5); 32 | var a = gl[2, 0, 0, 1]; 33 | var b = gl[4, 1, 4, 0]; 34 | var g1 = Group.Generate(gl, a, b); 35 | DisplayGroup.Head(g1); // 480 elements 36 | } 37 | 38 | { 39 | var gl = new GL(2, 7); 40 | var a = gl[3, 0, 0, 1]; 41 | var b = gl[6, 1, 6, 0]; 42 | var g1 = Group.Generate(gl, a, b); 43 | DisplayGroup.Head(g1); // 2016 elements 44 | } 45 | 46 | { 47 | var gl = new GL(2, 11); 48 | var a = gl[2, 0, 0, 1]; 49 | var b = gl[10, 1, 10, 0]; 50 | var g1 = Group.Generate(gl, a, b); 51 | DisplayGroup.Head(g1); // 13200 elements 52 | } 53 | 54 | { 55 | var gl = new GL(3, 2); 56 | var a = gl.At((0, 1, 4, 8), (1, 1, 1, 1)); 57 | var b = gl.At((2, 3, 7), (1, 1, 1)); 58 | var g1 = Group.Generate(gl, a, b); 59 | DisplayGroup.Head(g1); // 168 elements 60 | } 61 | 62 | { 63 | var gl = new GL(3, 3); 64 | var a = gl.At((0, 4, 8), (2, 1, 1)); 65 | var b = gl.At((0, 2, 3, 7), (2, 1, 2, 2)); 66 | var g1 = Group.Generate(gl, a, b); 67 | DisplayGroup.Head(g1); // 11232 elements 68 | } 69 | 70 | { 71 | var gl = new GL(4, 2); 72 | var a = gl.At((0, 1, 5, 10, 15), (1, 1, 1, 1, 1)); 73 | var b = gl.At((3, 4, 9, 14), (1, 1, 1, 1)); 74 | var g1 = Group.Generate(gl, a, b); 75 | DisplayGroup.Head(g1); // 20160 elements 76 | } 77 | } 78 | 79 | public static void SmallGroup3244() 80 | { 81 | // GroupName https://people.maths.bris.ac.uk/~matyd/GroupNames/1/C8.C2%5E2.html 82 | // G:=sub; 83 | // G:=Group( (1,2,3,4,5,6,7,8)(9,10,11,12,13,14,15,16), (2,4)(3,7)(6,8)(10,12)(11,15)(14,16), (1,11)(2,16)(3,13)(4,10)(5,15)(6,12)(7,9)(8,14) ); 84 | var gl = new GL(4, 3); 85 | var m1 = gl[0, 1, 0, 0, 2, 0, 2, 0, 0, 1, 0, 1, 0, 0, 2, 0]; 86 | var m2 = gl[0, 0, 0, 2, 2, 0, 1, 0, 0, 1, 0, 2, 2, 0, 0, 0]; 87 | var m3 = gl[2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1]; 88 | var g1 = Group.Generate("gl(C8 . (C2 x C2))", gl, m1, m2, m3); 89 | DisplayGroup.Head(g1); 90 | 91 | var s16 = new Sn(16); 92 | var p1 = s16[(1, 2, 3, 4, 5, 6, 7, 8), (9, 10, 11, 12, 13, 14, 15, 16)]; 93 | var p2 = s16[(2, 4), (3, 7), (6, 8), (10, 12), (11, 15), (14, 16)]; 94 | var p3 = s16[(1, 11), (2, 16), (3, 13), (4, 10), (5, 15), (6, 12), (7, 9), (8, 14)]; 95 | 96 | var g2 = Group.Generate("pg(C8 . (C2 x C2))", s16, p1, p2, p3); 97 | DisplayGroup.Head(g2); 98 | 99 | var g3 = new WordGroup("wg(C8 . (C2 x C2))", "a8, b2, c2, bab=a3, cac=a5, cbc=a4b"); 100 | DisplayGroup.Head(g3); 101 | 102 | Console.WriteLine("({0}) IsIsomorphicTo ({1}) : {2}", g1, g2, g1.IsIsomorphicTo(g2)); 103 | Console.WriteLine("({0}) IsIsomorphicTo ({1}) : {2}", g1, g3, g1.IsIsomorphicTo(g3)); 104 | } 105 | } -------------------------------------------------------------------------------- /FastGoat/Examples/GroupOrder21.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.CartesianProduct; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Integers; 5 | using FastGoat.UserGroup.Perms; 6 | 7 | namespace FastGoat.Examples; 8 | 9 | public static class GroupOrder21 10 | { 11 | public static void Zn21() 12 | { 13 | var z21 = new Zn(21); 14 | var g21 = Group.Generate(z21, z21[1]); 15 | DisplayGroup.HeadElements(g21); 16 | } 17 | 18 | public static void ZnDirectProduct() 19 | { 20 | var z7Xz3 = Product.Group(new Zn(7), new Zn(3)); 21 | var g21 = Group.Generate(z7Xz3, z7Xz3[1, 0], z7Xz3[0, 1]); 22 | DisplayGroup.HeadElements(g21); 23 | } 24 | 25 | public static void Symmetric7() 26 | { 27 | var s7 = new Sn(7); 28 | var a = s7[(1, 2, 3, 4, 5, 6, 7)]; 29 | var allC3 = IntExt.GetPermutations(7).Select(s7.CreateElement).Where(p => (p ^ 3) == s7.Neutral()); 30 | var b = allC3.First(p => Group.GenerateElements(s7, a, p).Count() == 21); 31 | var g21 = Group.Generate(s7, a, b); 32 | DisplayGroup.HeadElements(g21); 33 | } 34 | 35 | public static void Symmetric7Fast() 36 | { 37 | var s7 = new Sn(7); 38 | var a = s7[(1, 2, 3, 4, 5, 6, 7)]; 39 | var allC3 = IntExt.GetPermutations(7).Select(s7.CreateElement).Where(p => (p ^ 3) == s7.Neutral()); 40 | var b = allC3.First(p => (a ^ 2) == p * a * (p ^ -1)); 41 | var g21 = Group.Generate(s7, a, b); 42 | DisplayGroup.HeadElements(g21); 43 | } 44 | 45 | public static void SemiDirectProduct() 46 | { 47 | var c7 = Group.Generate("C7", new Zn(7), new Zn(7)[1]); 48 | var c3 = Group.Generate("C3", new Zn(3), new Zn(3)[1]); 49 | var g21 = Group.SemiDirectProd(c7, c3); 50 | DisplayGroup.HeadElementsSdp(g21); 51 | } 52 | } -------------------------------------------------------------------------------- /FastGoat/Examples/HolomorphC7.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.CartesianProduct; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.Structures.GenericGroup; 5 | using FastGoat.UserGroup.Integers; 6 | using FastGoat.UserGroup.Words; 7 | 8 | namespace FastGoat.Examples; 9 | 10 | public static class HolomorphC7 11 | { 12 | public static void Sample() 13 | { 14 | // Saunders MacLane, Garrett Birkhoff. Algebra (3rd ed.) page 416 15 | var c7 = new Cn(7); 16 | var c6 = new Cn(6); 17 | var thetas = Group.AllOpsByAutomorphisms(c6, c7); 18 | List> nonIsomorphics = new(); 19 | char k = 'a'; 20 | var nm = "(C7 x: C6)"; 21 | foreach (var theta in thetas) 22 | { 23 | var sdp = Group.SemiDirectProd($"{nm}{k++}", c7, theta, c6); 24 | if (nonIsomorphics.All(g => !g.IsIsomorphicTo(sdp))) 25 | nonIsomorphics.Add(sdp); 26 | } 27 | 28 | nonIsomorphics.Sort((a, b) => -a.ElementsOrdersList().Max().CompareTo(b.ElementsOrdersList().Max())); 29 | foreach (var sdp in nonIsomorphics) 30 | { 31 | DisplayGroup.HeadSdp(sdp); 32 | Console.WriteLine(sdp.ElementsOrdersList().Glue(", ")); 33 | Console.WriteLine(); 34 | } 35 | 36 | var c7c6 = Product.Generate(c6, c7); 37 | DisplayGroup.Head(c7c6); 38 | Console.WriteLine(c7c6.ElementsOrdersList().Glue(", ")); 39 | Console.WriteLine(); 40 | 41 | var wgC3D14 = new WordGroup("C3 x D14", "a7, b2, c3, abab, ac = ca, bc = cb"); 42 | DisplayGroup.Head(wgC3D14); 43 | Console.WriteLine(wgC3D14.ElementsOrdersList().Glue(", ")); 44 | Console.WriteLine(); 45 | 46 | var wgC2H21 = new WordGroup("C2 x H21", "a7, b3, c2, a2 = bab-1, ac = ca, bc = cb"); 47 | DisplayGroup.Head(wgC2H21); 48 | Console.WriteLine(wgC2H21.ElementsOrdersList().Glue(", ")); 49 | Console.WriteLine(); 50 | 51 | var u7 = new Un(7); 52 | var a = u7[(c7[1], c7[3])]; 53 | var theta1 = Group.HomomorphismMap(u7, u7, new() { [a] = a }); 54 | var homTheta1 = Group.Hom(u7, theta1); 55 | var hol7 = Group.SemiDirectProd("Hol7", c7, homTheta1, u7); 56 | DisplayGroup.HeadSdp(hol7); 57 | Console.WriteLine(hol7.ElementsOrdersList().Glue(", ")); 58 | Console.WriteLine(); 59 | 60 | var g0 = nonIsomorphics[0]; 61 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", c7c6, g0, c7c6.IsIsomorphicTo(g0)); 62 | var g1 = nonIsomorphics[1]; 63 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", wgC3D14, g1, wgC3D14.IsIsomorphicTo(g1)); 64 | var g2 = nonIsomorphics[2]; 65 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", wgC2H21, g2, wgC2H21.IsIsomorphicTo(g2)); 66 | var g3 = nonIsomorphics[3]; 67 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", hol7, g3, hol7.IsIsomorphicTo(g3)); 68 | } 69 | } -------------------------------------------------------------------------------- /FastGoat/Examples/NilpotentGroups.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.Structures.GenericGroup; 3 | using FastGoat.UserGroup.Perms; 4 | using FastGoat.UserGroup.Words; 5 | 6 | namespace FastGoat.Examples; 7 | 8 | public static class NilpotentGroups 9 | { 10 | static void ZentrumChain(ConcreteGroup g, int i = 1) where T : struct, IElt 11 | { 12 | if (g.Count() == 1) 13 | return; 14 | 15 | var Z = Group.Zentrum(g); 16 | if (Z.Count() == 1) 17 | return; 18 | 19 | var zi = g.Over(Z, $"Z{i}"); 20 | DisplayGroup.Head(zi); 21 | 22 | ZentrumChain(zi, i + 1); 23 | } 24 | 25 | public static void Nilpotent2() 26 | { 27 | var gr = new WordGroup("Q8", "a4, a2=b2, a-1=bab-1"); 28 | DisplayGroup.Head(gr); 29 | ZentrumChain(gr); 30 | } 31 | 32 | public static void Nilpotent3() 33 | { 34 | var gr = new WordGroup("Q16", "a8, b2=a4, bab-1=a-1"); 35 | DisplayGroup.Head(gr); 36 | ZentrumChain(gr); 37 | } 38 | 39 | public static void Nilpotent4() 40 | { 41 | var gr = new WordGroup("Q32", "a16, b2=a8, bab-1=a-1"); 42 | DisplayGroup.Head(gr); 43 | ZentrumChain(gr); 44 | } 45 | 46 | public static void NilpotentIsSolvable() 47 | { 48 | var gr8 = new WordGroup("Q8", "a4, a2=b2, a-1=bab-1"); 49 | foreach (var com in Group.DerivedChain(gr8)) 50 | DisplayGroup.Head(com); 51 | 52 | Console.WriteLine("##############"); 53 | var gr16 = new WordGroup("Q16", "a8, b2=a4, bab-1=a-1"); 54 | foreach (var com in Group.DerivedChain(gr16)) 55 | DisplayGroup.Head(com); 56 | 57 | Console.WriteLine("##############"); 58 | } 59 | 60 | public static void SolvableAndNotNilpotent() 61 | { 62 | var gr = new Symm(4); 63 | foreach (var com in Group.DerivedChain(gr)) 64 | DisplayGroup.Head(com); 65 | 66 | Console.WriteLine("##############"); 67 | DisplayGroup.Head(gr); 68 | ZentrumChain(gr); 69 | } 70 | } -------------------------------------------------------------------------------- /FastGoat/Examples/PSLnp.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.UserGroup; 3 | using FastGoat.UserGroup.Matrix; 4 | using FastGoat.UserGroup.Perms; 5 | 6 | namespace FastGoat.Examples; 7 | 8 | public static class PSLnp 9 | { 10 | public static void L23() 11 | { 12 | var gl = new GL(2, 3); 13 | var a = gl[1, 1, 0, 1]; 14 | var b = gl[0, 1, 2, 0]; 15 | 16 | var sl23 = Group.Generate("SL2(3)", gl, a, b); 17 | DisplayGroup.Head(sl23); 18 | var zg = Group.Zentrum(sl23); 19 | DisplayGroup.Head(zg); 20 | var l23 = sl23.Over(zg, "L2(3)"); 21 | DisplayGroup.Head(l23); 22 | 23 | var sn = new Sn(4); 24 | var a4 = Group.Generate("A4", sn, sn[(1, 2, 3)], sn[(1, 2), (3, 4)]); 25 | DisplayGroup.Head(a4); 26 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", l23, a4, l23.IsIsomorphicTo(a4)); 27 | } 28 | 29 | public static void L27_L32() 30 | { 31 | var gl27 = new GL(2, 7); 32 | var a = gl27[3, 0, 0, 5]; 33 | var b = gl27[6, 1, 6, 0]; 34 | 35 | var sl27 = Group.Generate("SL2(7)", gl27, a, b); 36 | DisplayGroup.Head(sl27); 37 | var zg27 = Group.Zentrum(sl27); 38 | DisplayGroup.Head(zg27); 39 | var l27 = sl27.Over(zg27, "L2(7)"); 40 | DisplayGroup.Head(l27); 41 | 42 | var gl32 = new GL(3, 2); 43 | var a3 = gl32.At((0, 4, 8, 1), 1); 44 | var b3 = gl32.At((2, 3, 7), 1); 45 | 46 | var sl32 = Group.Generate("SL3(2)", gl32, a3, b3); 47 | DisplayGroup.Head(sl32); 48 | var zg32 = Group.Zentrum(sl32); 49 | DisplayGroup.Head(zg32); 50 | var l32 = sl32.Over(zg32, "L3(2)"); 51 | DisplayGroup.Head(l32); 52 | 53 | var sn = new Sn(7); 54 | var a2 = sn[(1, 2), (4, 5)]; 55 | var b2 = sn[(2, 3, 4), (5, 6, 7)]; 56 | var pg = Group.Generate("pg(GL3(2))", sn, a2, b2); 57 | DisplayGroup.Head(pg); 58 | 59 | DisplayGroup.AreIsomorphics(pg, l32); 60 | DisplayGroup.AreIsomorphics(l27, l32); 61 | } 62 | 63 | public static void L33() 64 | { 65 | var gl33 = new GL(3, 3); 66 | var a = gl33.At((0, 4, 8, 1), 1); 67 | var b = gl33.At((2, 3, 7), (1, 2, 2)); 68 | 69 | var sl33 = Group.Generate("SL3(3)", gl33, a, b); 70 | DisplayGroup.Head(sl33); 71 | var zg33 = Group.Zentrum(sl33); 72 | DisplayGroup.Head(zg33); 73 | var l33 = sl33.Over(zg33, "L3(3)"); 74 | DisplayGroup.Head(l33); 75 | 76 | // H.E. Rose, A Course on Finite Groups, page 264 77 | var sn = new Sn(13); 78 | var a2 = sn[(1, 4, 6), (2, 3, 7, 10, 11, 8), (9, 13)]; 79 | var b2 = sn[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]; 80 | var pg = Group.Generate("pg(PSL3(3))", sn, a2, b2); 81 | DisplayGroup.Head(pg); 82 | 83 | var ra = l33[0, 2, 0, 1, 1, 0, 0, 0, 1]; 84 | var rb = l33[0, 1, 0, 0, 0, 1, 1, 0, 0]; 85 | Console.WriteLine("{0} order : {1}", a2, pg.ElementsOrders[a2]); 86 | Console.WriteLine("{0} order : {1}", b2, pg.ElementsOrders[b2]); 87 | Console.WriteLine("{0} order : {1}", ra, l33.ElementsOrders[ra]); 88 | Console.WriteLine("{0} order : {1}", rb, l33.ElementsOrders[rb]); 89 | 90 | var pMap = Group.PartialMap((a2, ra), (b2, rb)); 91 | var isom = Group.IsomorphismMap(pg, l33, pMap); 92 | Console.WriteLine("{0} IsIsomorphicTo {1} : {2}", pg, l33, isom.Count == l33.Count()); 93 | } 94 | 95 | public static void L42() 96 | { 97 | var sl42 = FG.SLnp(4, 2); 98 | DisplayGroup.HeadOrders(sl42); 99 | 100 | var a8 = FG.Alternate(8); 101 | DisplayGroup.AreIsomorphics(sl42, a8); 102 | 103 | var sl34 = FG.SLnq(3, 4); 104 | DisplayGroup.HeadOrders(sl34); 105 | var zsl34 = Group.Zentrum(sl34); 106 | var l34 = sl34.Over(zsl34, "L3(4)"); 107 | DisplayGroup.HeadOrders(l34); 108 | 109 | DisplayGroup.AreIsomorphics(sl42, l34); 110 | } 111 | } -------------------------------------------------------------------------------- /FastGoat/Examples/PolynomialOperations.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.UserGroup.Integers; 4 | 5 | namespace FastGoat.Examples; 6 | 7 | public static class PolynomialOperations 8 | { 9 | public static void Qi() 10 | { 11 | var (x, i) = Ring.Polynomial(Rational.KZero(), "X", "i").Deconstruct(); 12 | var f = x.Pow(2) + 1; 13 | var fi = i.Pow(2) + 1; 14 | var p = (x - i) * (x + i); 15 | 16 | Console.WriteLine(p); 17 | Console.WriteLine(p.Div(f)); 18 | Console.WriteLine(p.Div(fi).rem.Div(f)); 19 | } 20 | 21 | public static void Qsqrt2() 22 | { 23 | var (x, a) = Ring.Polynomial(Rational.KZero(), "X", "a").Deconstruct(); 24 | var f = x.Pow(2) - 2; 25 | var fa = a.Pow(2) - 2; 26 | var p = (x - a) * (x + a); 27 | 28 | Console.WriteLine(p); 29 | Console.WriteLine(p.Div(f)); 30 | Console.WriteLine(p.Div(fa).rem.Div(f)); 31 | } 32 | 33 | public static void Qcbrt1() 34 | { 35 | var (x, a) = Ring.Polynomial(Rational.KZero(), "X", "a").Deconstruct(); 36 | var f = x.Pow(3) - 1; 37 | var fa = a.Pow(2) + a + 1; 38 | var p = (x - 1) * (x - a) * (x + a + 1); 39 | 40 | Console.WriteLine(p); 41 | Console.WriteLine(p.Div(f)); 42 | Console.WriteLine(p.Div(fa).rem.Div(f)); 43 | } 44 | 45 | public static void Qcbrt5() 46 | { 47 | var (x, a, j) = Ring.Polynomial(Rational.KZero(), "X", "a", "j").Deconstruct(); 48 | var f = x.Pow(3) - 5; 49 | var fa = a.Pow(3) - 5; 50 | var fj = j.Pow(2) + j + 1; 51 | var p = (x - a) * (x - j * a) * (x + (j + 1) * a); 52 | 53 | Console.WriteLine(p); 54 | Console.WriteLine(p.Div(f)); 55 | Console.WriteLine(p.Div(fa).rem.Div(f)); 56 | Console.WriteLine(p.Div(fa).rem.Div(fj).rem.Div(f)); 57 | } 58 | 59 | public static void Qsqrt6() 60 | { 61 | var (x, a, b) = Ring.Polynomial(Rational.KZero(), "X", "a", "b").Deconstruct(); 62 | var f = x.Pow(2) - 6; 63 | var fa = a.Pow(2) - 2; 64 | var fb = b.Pow(2) - 3; 65 | var p = (x - a * b) * (x + a * b); 66 | 67 | Console.WriteLine(p); 68 | Console.WriteLine(p.Div(fa).rem.Div(fb)); 69 | Console.WriteLine(p.Div(f)); 70 | Console.WriteLine(p.Div(fa).rem.Div(f)); 71 | Console.WriteLine(p.Div(fa).rem.Div(fb).rem.Div(f)); 72 | } 73 | 74 | public static void Qisqrt2() 75 | { 76 | var (x, a, i) = Ring.Polynomial(Rational.KZero(), "X", "a", "i").Deconstruct(); 77 | var f = x.Pow(4) - x.Pow(2) - 2; 78 | var fi = i.Pow(2) + 1; 79 | var fa = a.Pow(2) - 2; 80 | var p = (x - a) * (x + a) * (x - i) * (x + i); 81 | 82 | Console.WriteLine(p); 83 | Console.WriteLine(p.Div(f)); 84 | Console.WriteLine("#"); 85 | 86 | Console.WriteLine(p.Div(fi).rem.Div(f)); 87 | Console.WriteLine(p.Div(fi).rem.Div(fa).rem); 88 | Console.WriteLine(p.Div(fi).rem.Div(fa).rem.Div(f)); 89 | 90 | Console.WriteLine("#"); 91 | Console.WriteLine(p.Div(fa).rem.Div(f)); 92 | Console.WriteLine(p.Div(fa).rem.Div(fi).rem.Div(f)); 93 | } 94 | 95 | public static void Qexpr() 96 | { 97 | var (x, a) = Ring.Polynomial(Rational.KZero(), "X", "a").Deconstruct(); 98 | var f = x.Pow(2) - 2 * x - 2; 99 | var fa = a.Pow(2) - 3; 100 | var p = (x - (1 + a)) * (x - (1 - a)); 101 | 102 | Console.WriteLine(p); 103 | Console.WriteLine(p.Div(fa).rem); 104 | Console.WriteLine(p.Div(fa).rem.Div(f)); 105 | } 106 | } -------------------------------------------------------------------------------- /FastGoat/FastGoat.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | enable 6 | enable 7 | default 8 | Debug;Release 9 | AnyCPU;x64 10 | 11 | 12 | 13 | 14 | 15 | 16 | TextTemplatingFileGenerator 17 | GpEp.cs 18 | 19 | 20 | TextTemplatingFileGenerator 21 | Tuple2Array.cs 22 | 23 | 24 | TextTemplatingFileGenerator 25 | Array2Tuple.cs 26 | 27 | 28 | 29 | 30 | GpEp.tt 31 | 32 | 33 | True 34 | True 35 | Tuple2Array.tt 36 | 37 | 38 | True 39 | True 40 | Array2Tuple.tt 41 | 42 | 43 | -------------------------------------------------------------------------------- /FastGoat/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Text; 3 | using FastGoat.Commons; 4 | using FastGoat.Examples; 5 | using FastGoat.Structures; 6 | using FastGoat.Structures.GenericGroup; 7 | using FastGoat.Structures.VecSpace; 8 | using FastGoat.UserGroup; 9 | using FastGoat.UserGroup.EllCurve; 10 | using FastGoat.UserGroup.Integers; 11 | 12 | ////////////////////////////////// 13 | // // 14 | // Work Table for crafting // 15 | // // 16 | ////////////////////////////////// 17 | 18 | Console.WriteLine("Hello World"); -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/Automorphism.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public readonly struct Automorphism : IMap, IElt> where T : struct, IElt 6 | { 7 | public IReadOnlyDictionary AutMap { get; } 8 | 9 | public Automorphism(AutomorphismGroup aut) 10 | { 11 | AutMap = aut.G.ToDictionary(e => e, e => e); 12 | Hash = AutMap.OrderBy(kp => kp.Key).Aggregate(aut.G.Hash, (acc, kp) => (acc, kp.Key, kp.Value).GetHashCode()); 13 | AutGroup = aut; 14 | } 15 | 16 | public Automorphism(AutomorphismGroup aut, IReadOnlyDictionary e) 17 | { 18 | AutMap = new Dictionary(e); 19 | Hash = AutMap.OrderBy(kp => kp.Key).Aggregate(aut.G.Hash, (acc, kp) => (acc, kp.Key, kp.Value).GetHashCode()); 20 | AutGroup = aut; 21 | } 22 | 23 | public bool Equals(Automorphism other) => Hash == other.Hash && IMap.EqualiltyMap(this, other); 24 | 25 | public int CompareTo(Automorphism other) => IMap.CompareMap(this, other); 26 | 27 | public int Hash { get; } 28 | public AutomorphismGroup AutGroup { get; } 29 | 30 | public ConcreteGroup Domain => AutGroup.G; 31 | public Automorphism Invert() => AutGroup.Invert(this); 32 | 33 | public IEnumerable Kernel() 34 | { 35 | var n = Domain.Neutral(); 36 | return AutMap.Where(kp => kp.Value.Equals(n)).Select(kp => kp.Key); 37 | } 38 | 39 | public IEnumerable Image() => AutMap.Values.Distinct(); 40 | 41 | public bool Equals(IMap? other) => other?.Hash == Hash; 42 | public int CompareTo(IMap? other) => other is null ? 1 : IMap.CompareMap(this, other); 43 | public override int GetHashCode() => Hash; 44 | public T this[T index] => AutMap[index]; 45 | 46 | public override string ToString() 47 | { 48 | return AutMap.AscendingByKey().GlueMap(); 49 | } 50 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/AutomorphismGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public class AutomorphismGroup : IGroup> where T : struct, IElt 6 | { 7 | public ConcreteGroup G { get; } 8 | 9 | public AutomorphismGroup(ConcreteGroup g) 10 | { 11 | G = g; 12 | Name = $"Aut({g.Name})"; 13 | Hash = (g.Hash, "Aut").GetHashCode(); 14 | } 15 | 16 | public IEnumerable> GetGenerators() 17 | { 18 | throw new GroupException(GroupExceptionType.GroupDef); 19 | } 20 | 21 | public IEnumerable> GetElements() 22 | { 23 | yield return Neutral(); 24 | } 25 | 26 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 27 | 28 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 29 | 30 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 31 | 32 | public int Hash { get; } 33 | public string Name { get; } 34 | 35 | public Automorphism Neutral() => new Automorphism(this); 36 | 37 | public Automorphism Invert(Automorphism e) 38 | { 39 | if (!Equals(e.AutGroup)) 40 | throw new GroupException(GroupExceptionType.BaseGroup); 41 | 42 | var autMap = e.AutMap.ToDictionary(kp => kp.Value, kp => kp.Key); 43 | return new Automorphism(this, autMap); 44 | } 45 | 46 | public Automorphism Op(Automorphism e1, Automorphism e2) 47 | { 48 | if (!Equals(e1.AutGroup) || !Equals(e2.AutGroup)) 49 | throw new GroupException(GroupExceptionType.BaseGroup); 50 | 51 | var autMap = e2.AutMap.ToDictionary(kp => kp.Key, kp => e1.AutMap[kp.Value]); 52 | return new Automorphism(this, autMap); 53 | } 54 | 55 | public Automorphism Create(IReadOnlyDictionary autMap) 56 | { 57 | if (autMap.Count != G.Count()) 58 | throw new GroupException(GroupExceptionType.GroupDef); 59 | 60 | return new Automorphism(this, autMap); 61 | } 62 | 63 | public Automorphism Create(Homomorphism hom) => Create(hom.HomMap); 64 | 65 | public Automorphism this[params ValueType[] us] 66 | { 67 | get 68 | { 69 | var pMap = us.Select(e => (dynamic)e).ToDictionary(kp => (T)kp.Item1, kp => (T)kp.Item2); 70 | var autMap = Group.AutomorphismMap(G, pMap); 71 | if (autMap.Count != G.Count()) 72 | throw new GroupException(GroupExceptionType.GroupDef); 73 | 74 | return new Automorphism(this, autMap); 75 | } 76 | } 77 | 78 | public override int GetHashCode() => Hash; 79 | public override string ToString() => Name; 80 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/ConjugacyClasses.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.Structures.GenericGroup; 5 | 6 | public readonly struct ConjugacyClasses : IEnumerable where T : struct, IElt 7 | { 8 | public ConcreteGroup Gr { get; } 9 | 10 | public ConjugacyClasses(ConcreteGroup gr) 11 | { 12 | Gr = gr; 13 | Classes = Group.AllConjugacyClassesNames(gr); 14 | ClassName = new(); 15 | Repr2Idx = new(); 16 | Idx2Repr = new(); 17 | EltRepr = new(); 18 | ClassOrbx = new(); 19 | ClassStabx = new(); 20 | AllReprs = new(); 21 | for (int i = 0; i < Classes.Length; ++i) 22 | { 23 | var (name, repr, stabx, orbx) = Classes[i]; 24 | AllReprs.Add(repr); 25 | ClassName[repr] = name; 26 | Repr2Idx[repr] = i; 27 | Idx2Repr[i] = repr; 28 | ClassOrbx[repr] = orbx; 29 | ClassStabx[repr] = stabx; 30 | foreach (var e in orbx) 31 | EltRepr[e] = repr; 32 | } 33 | } 34 | 35 | public void Display(bool details = false) 36 | { 37 | var digits = Classes.Max(e => $"{e.repr}".Length); 38 | var fmt = $"{{0,-{digits}}}"; 39 | foreach (var e in Classes) 40 | { 41 | if (details) 42 | Console.WriteLine( 43 | $"{e.name,-3} = {string.Format(fmt, e.repr)} {$"Stab({e.name})",-10}:{e.stabx.Count,-4} {$"Orb({e.name})",-10}:{e.orbx.Count,-4} {e.orbx.Glue(", ")}"); 44 | else 45 | Console.WriteLine( 46 | $"{e.name,-3} = {string.Format(fmt, e.repr)} {$"Stab({e.name})",-10}:{e.stabx.Count,-4} {$"Orb({e.name})",-10}:{e.orbx.Count,-4}"); 47 | } 48 | 49 | Console.WriteLine($"Nb Classes:{Classes.Length}"); 50 | Console.WriteLine(); 51 | } 52 | 53 | private (string name, T repr, HashSet stabx, HashSet orbx)[] Classes { get; } 54 | 55 | private Dictionary ClassName { get; } 56 | private Dictionary Repr2Idx { get; } 57 | private Dictionary Idx2Repr { get; } 58 | private Dictionary EltRepr { get; } 59 | private Dictionary> ClassOrbx { get; } 60 | private Dictionary> ClassStabx { get; } 61 | private HashSet AllReprs { get; } 62 | public int Count => AllReprs.Count; 63 | 64 | public string GetClassName(T e) => ClassName.ContainsKey(e) ? ClassName[e] : ClassName[EltRepr[e]]; 65 | public string GetClassName(int i) => ClassName.ContainsKey(Idx2Repr[i]) ? ClassName[Idx2Repr[i]] : ClassName[EltRepr[Idx2Repr[i]]]; 66 | public int GetIndex(T e) => Repr2Idx.ContainsKey(e) ? Repr2Idx[e] : Repr2Idx[EltRepr[e]]; 67 | public T GetRepresentative(int i) => Idx2Repr[i]; 68 | public T GetRepresentative(T e) => EltRepr[e]; 69 | public int GetClassOrder(T e) => ClassOrbx[e].Count; 70 | public int GetClassCentralizerOrder(T e) => ClassStabx[e].Count; 71 | public IEnumerable GetClassOrbx(T e) => ClassOrbx[e]; 72 | public IEnumerable GetClassOrbx(int i) => ClassOrbx[Idx2Repr[i]]; 73 | public IEnumerable GetClassStabx(T e) => ClassStabx[e]; 74 | public IEnumerable GetClassStabx(int i) => ClassStabx[Idx2Repr[i]]; 75 | public IEnumerable GetRepresentatives() => AllReprs; 76 | public IEnumerable GetOrbxCount() => ClassOrbx.Select(s => s.Value.Count); 77 | public IEnumerable GetStabxCount() => ClassStabx.Select(s => s.Value.Count); 78 | 79 | public bool ValidClasses(IEnumerable classes) => AllReprs.SetEquals(classes); 80 | public IEnumerator GetEnumerator() => AllReprs.OrderDescending().GetEnumerator(); 81 | 82 | IEnumerator IEnumerable.GetEnumerator() 83 | { 84 | return GetEnumerator(); 85 | } 86 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/Coset.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.Structures.GenericGroup; 5 | 6 | public readonly struct Coset : ICoset> where T : struct, IElt 7 | { 8 | public Coset(ConcreteGroup g, ConcreteGroup h, CosetType cosetType = CosetType.Both) 9 | { 10 | CosetType = cosetType; 11 | G = g; 12 | H = h; 13 | X = H.Neutral(); 14 | Hash = (g.Hash, h.Hash, X.Hash).GetHashCode(); 15 | } 16 | 17 | public Coset(ConcreteGroup g, ConcreteGroup h, T x, CosetType cosetType = CosetType.Both) 18 | { 19 | CosetType = cosetType; 20 | G = g; 21 | H = h; 22 | X = x; 23 | Hash = (g.Hash, h.Hash, X.Hash).GetHashCode(); 24 | } 25 | 26 | public CosetType CosetType { get; } 27 | 28 | public T X { get; } 29 | public ConcreteGroup G { get; } 30 | public ConcreteGroup H { get; } 31 | public bool Equals(Coset other) => X.Equals(other.X); 32 | 33 | public int CompareTo(Coset other) => X.CompareTo(other.X); 34 | 35 | private IEnumerable Elements 36 | { 37 | get 38 | { 39 | List set = new(); 40 | foreach (var h in H) 41 | { 42 | if (CosetType != CosetType.Right) 43 | set.Add(G.Op(X, h)); 44 | else 45 | set.Add(G.Op(h, X)); 46 | } 47 | 48 | return set.Ascending(); 49 | } 50 | } 51 | 52 | public IEnumerator GetEnumerator() => Elements.GetEnumerator(); 53 | 54 | IEnumerator IEnumerable.GetEnumerator() 55 | { 56 | return GetEnumerator(); 57 | } 58 | 59 | public int Hash { get; } 60 | public override int GetHashCode() => Hash; 61 | 62 | public override string ToString() 63 | { 64 | var hName = H.Name; 65 | if (CosetType != CosetType.Right) 66 | return $"{X}({hName})"; 67 | else 68 | return $"({hName}){X}"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/CosetType.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.GenericGroup; 2 | 3 | public enum CosetType 4 | { 5 | Left, 6 | Right, 7 | Both 8 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/ExtensionGroup.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.CartesianProduct; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public class ExtensionGroup : ConcreteGroup> where Tg : struct, IElt where Tn : struct, IElt 6 | { 7 | public MapElt, Tn> Map => ExtBase.Map; 8 | public MapElt> L => ExtBase.L; 9 | public ConcreteGroup G => ExtBase.G; 10 | public ConcreteGroup N => ExtBase.N; 11 | 12 | public ExtensionGroupBase ExtBase { get; } 13 | 14 | public ExtensionGroup(ConcreteGroup n, MapElt> l, MapElt, Tn> map, ConcreteGroup g) 15 | : this(new ExtensionGroupBase(n, l, map, g)) 16 | { 17 | } 18 | 19 | private ExtensionGroup(ExtensionGroupBase ExtBase) : base("Ext", ExtBase) 20 | { 21 | this.ExtBase = ExtBase; 22 | var nName = ExtBase.N.Name.Contains('x') ? $"({N})" : $"{N}"; 23 | var gName = ExtBase.G.Name.Contains('x') ? $"({G})" : $"{G}"; 24 | Name = $"{nName} . {gName}"; 25 | Hash = (Name, Elements.Count).GetHashCode(); 26 | } 27 | 28 | public override int GetHashCode() => Hash; 29 | public override string ToString() => Name; 30 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/ExtensionGroupBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Structures.CartesianProduct; 3 | 4 | namespace FastGoat.Structures.GenericGroup; 5 | 6 | public struct ExtensionGroupBase : IGroup> where Tg : struct, IElt where Tn : struct, IElt 7 | { 8 | public MapElt, Tn> Map { get; } 9 | public MapElt> L { get; } 10 | public ConcreteGroup G { get; } 11 | public ConcreteGroup N { get; } 12 | public Dictionary,Ep2> InvertTable { get; } 13 | public Dictionary<(Ep2,Ep2),Ep2> OpTable { get; } 14 | 15 | public ExtensionGroupBase(ConcreteGroup n, MapElt> l, MapElt, Tn> map, ConcreteGroup g) 16 | { 17 | G = g; 18 | N = n; 19 | Map = map; 20 | L = l.Clone(); 21 | var nName = N.Name.Contains('x') ? $"({N})" : $"{N}"; 22 | var gName = G.Name.Contains('x') ? $"({G})" : $"{G}"; 23 | Name = $"{nName} . {gName}"; 24 | 25 | var og = N.Count() * G.Count(); 26 | InvertTable = new(og); 27 | OpTable = new(og * og); 28 | 29 | Elements = Product.Generate(N, G).ToHashSet(); 30 | PseudoGenerators = new List>(); 31 | foreach (var e in G.GetGenerators()) 32 | PseudoGenerators.Add(Product.Elt(N.Neutral(), e)); 33 | 34 | foreach (var e in N.GetGenerators()) 35 | PseudoGenerators.Add(Product.Elt(e, G.Neutral())); 36 | 37 | Hash = (Name, Elements.Count).GetHashCode(); 38 | // IsGroup = Group.IsGroup(this, Elements); 39 | IsGroup = true; 40 | } 41 | 42 | public bool IsGroup { get; } 43 | 44 | public List> PseudoGenerators { get; } 45 | public HashSet> Elements { get; } 46 | 47 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 48 | 49 | IEnumerator IEnumerable.GetEnumerator() 50 | { 51 | return GetEnumerator(); 52 | } 53 | 54 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 55 | 56 | public int Hash { get; } 57 | public string Name { get; } 58 | 59 | public Ep2 this[params ValueType[] us] 60 | { 61 | get 62 | { 63 | var (us0, us1) = (us[0], us[1]); 64 | return new(N[us0], G[us1]); 65 | } 66 | } 67 | 68 | public IEnumerable> GetElements() => Elements; 69 | 70 | public IEnumerable> GetGenerators() => PseudoGenerators; 71 | 72 | public Ep2 Neutral() => new(N.Neutral(), G.Neutral()); 73 | 74 | public Ep2 Invert(Ep2 e) 75 | { 76 | if (InvertTable.TryGetValue(e, out var r)) 77 | return r; 78 | 79 | var (n, g) = (e.E1, e.E2); 80 | var ni = N.Invert(n); 81 | var gi = G.Invert(g); 82 | var nop = N.Op(N.Invert(Map[new(g, gi)]), ni); 83 | var m = L[gi][nop]; 84 | var ei = InvertTable[e] = new(m, gi); 85 | return ei; 86 | } 87 | 88 | public Ep2 Op(Ep2 e1, Ep2 e2) 89 | { 90 | var e12 = (e1, e2); 91 | if (OpTable.TryGetValue(e12, out var r)) 92 | return r; 93 | 94 | var (n1, n2, g1, g2) = (e1.E1, e2.E1, e1.E2, e2.E2); 95 | var nop = N.Op(n1, L[g1][n2]); 96 | var f = Map[new(g1, g2)]; 97 | var g1g2 = G.Op(g1, g2); 98 | var e3 = OpTable[e12] = new(N.Op(nop, f), g1g2); 99 | return e3; 100 | } 101 | 102 | public override int GetHashCode() => Hash; 103 | public override string ToString() => Name; 104 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/GroupSetEquality.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.GenericGroup; 2 | 3 | public class GroupSetEquality : EqualityComparer> where T : struct, IElt 4 | { 5 | public override bool Equals(ConcreteGroup? x, ConcreteGroup? y) 6 | { 7 | return x is not null && y is not null && x.SetEquals(y); 8 | } 9 | 10 | public override int GetHashCode(ConcreteGroup obj) => (obj.Count(), obj.GroupType).GetHashCode(); 11 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/GroupWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.Structures.GenericGroup; 5 | 6 | public readonly struct WElt : IElt 7 | { 8 | public dynamic E { get; } 9 | 10 | public WElt(dynamic e) 11 | { 12 | E = e; 13 | Hash = E.GetHashCode(); 14 | } 15 | 16 | public bool Equals(WElt other) => Hash == other.Hash; 17 | 18 | public int CompareTo(WElt other) => E.CompareTo(other.E); 19 | 20 | public int Hash { get; } 21 | 22 | public override int GetHashCode() => Hash; 23 | public override string ToString() => $"{E}"; 24 | } 25 | 26 | public readonly struct GroupWrapperBase : IGroup 27 | { 28 | public WElt NeutralElt { get; } 29 | private dynamic OriginGroup { get; } 30 | private Dictionary IdxTable { get; } 31 | 32 | public GroupWrapperBase(dynamic group, Dictionary idxTable, WElt[] gens) 33 | { 34 | (Name, Hash) = (group.Name, (group.Hash, "table").GetHashCode()); 35 | OriginGroup = group; 36 | IdxTable = idxTable; 37 | PseudoGeneratos = gens; 38 | Elements = IdxTable.Values.ToHashSet(); 39 | NeutralElt = IdxTable[group.Neutral().GetHashCode()]; 40 | } 41 | 42 | public HashSet Elements { get; } 43 | public WElt[] PseudoGeneratos { get; } 44 | 45 | public IEnumerator GetEnumerator() => Elements.GetEnumerator(); 46 | 47 | IEnumerator IEnumerable.GetEnumerator() 48 | { 49 | return GetEnumerator(); 50 | } 51 | 52 | public bool Equals(IGroup? other) => other?.Hash == Hash; 53 | 54 | public int Hash { get; } 55 | public string Name { get; } 56 | 57 | public WElt this[params ValueType[] us] => throw new NotImplementedException(); 58 | 59 | public IEnumerable GetElements() => Elements; 60 | 61 | public IEnumerable GetGenerators() => PseudoGeneratos; 62 | 63 | public WElt Neutral() => NeutralElt; 64 | 65 | public WElt Invert(WElt e) 66 | { 67 | var e0 = OriginGroup.Invert(e.E).GetHashCode(); 68 | return IdxTable[e0]; 69 | } 70 | 71 | public WElt Op(WElt e1, WElt e2) 72 | { 73 | var e12Hash = OriginGroup.Op(e1.E, e2.E).GetHashCode(); 74 | return IdxTable[e12Hash]; 75 | } 76 | 77 | public override int GetHashCode() => Hash; 78 | public override string ToString() => $"{Name.WithParenthesis()}(table)"; 79 | 80 | public static GroupWrapperBase Create(ConcreteGroup g) where T : struct, IElt 81 | { 82 | var hashes = g.Select(e => e.Hash).ToHashSet(); 83 | if (hashes.Count != g.Count()) 84 | throw new("Hash collisions"); 85 | 86 | var idxTable = g.Order().ToDictionary(e => e.Hash, e => new WElt(e)); 87 | var gens = g.GetGenerators().Select(e => new WElt(e)).ToArray(); 88 | return new GroupWrapperBase(g, idxTable, gens); 89 | } 90 | } 91 | 92 | public class GroupWrapper : ConcreteGroup 93 | { 94 | private GroupWrapperBase WrapperBase { get; } 95 | private GroupWrapper(GroupWrapperBase wrapperBase) : base(wrapperBase, wrapperBase.GetGenerators().ToArray()) 96 | { 97 | WrapperBase = wrapperBase; 98 | } 99 | 100 | public static GroupWrapper Create(ConcreteGroup g) where T : struct, IElt 101 | { 102 | return new(GroupWrapperBase.Create(g)); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/Homomorphism.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public readonly struct Homomorphism : IElt>, IMap 6 | where T1 : struct, IElt where T2 : struct, IElt 7 | { 8 | public IReadOnlyDictionary HomMap { get; } 9 | 10 | public Homomorphism(ConcreteGroup domGroup, IDictionary homMap) 11 | { 12 | Domain = domGroup; 13 | HomMap = new Dictionary(homMap); 14 | Hash = HomMap.OrderBy(kp => kp.Key) 15 | .Aggregate(domGroup.Hash, (acc, kp) => (acc, kp.Key, kp.Value).GetHashCode()); 16 | } 17 | 18 | public bool Equals(IMap? other) => other?.Hash == Hash; 19 | public bool Equals(Homomorphism other) => (other.IsNull && IsNull) || other.Hash == Hash; 20 | 21 | public int CompareTo(IMap? other) => other is null ? 1 : IMap.CompareMap(this, other); 22 | public int CompareTo(Homomorphism other) => other.IsNull ? 1 : IMap.CompareMap(this, other); 23 | 24 | public bool IsNull => HomMap is null; 25 | public int Count => HomMap.Count; 26 | public int Hash { get; } 27 | public ConcreteGroup Domain { get; } 28 | 29 | public IEnumerable Kernel() 30 | { 31 | var n = this[Domain.Neutral()]; 32 | return HomMap.Where(kp => kp.Value.Equals(n)).Select(kp => kp.Key); 33 | } 34 | 35 | public IEnumerable Image() => HomMap.Values.Distinct(); 36 | 37 | public T2 this[T1 index] => HomMap[index]; 38 | 39 | public override int GetHashCode() => Hash; 40 | 41 | public override string ToString() 42 | { 43 | if (IsNull) 44 | return "null"; 45 | 46 | return HomMap.AscendingByKey().GlueMap("; ", "{0}->[{1}]"); 47 | } 48 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/IsomorphEquality.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public class IsomorphEquality : EqualityComparer> where T : struct, IElt 6 | { 7 | public override bool Equals(ConcreteGroup? x, ConcreteGroup? y) 8 | { 9 | return x is not null && y is not null && x.IsIsomorphicTo(y); 10 | } 11 | 12 | public override int GetHashCode(ConcreteGroup obj) => (obj.Count(), obj.GroupType).GetHashCode(); 13 | } 14 | -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/MapElt.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public readonly struct MapElt : IElt>, IMap where T2 : struct, IElt where T1 : struct, IElt 6 | { 7 | public ConcreteGroup G2 { get; } 8 | public Dictionary map { get; } 9 | public Dictionary Map => new(map); 10 | 11 | public MapElt(ConcreteGroup g1, ConcreteGroup g2) 12 | { 13 | G2 = g2; 14 | Domain = g1; 15 | map = Domain.ToDictionary(e => e, _ => g2.Neutral()); 16 | Hash = (Domain.Count(), G2.Count()).GetHashCode(); 17 | } 18 | 19 | public MapElt(ConcreteGroup g1, ConcreteGroup g2, Dictionary map0) 20 | { 21 | (Domain, G2) = (g1, g2); 22 | map = new(map0); 23 | Hash = (Domain.Count(), G2.Count()).GetHashCode(); 24 | } 25 | 26 | public MapElt Clone() => new(Domain, G2, Map); 27 | 28 | public bool Equals(IMap? other) 29 | { 30 | return other is not null && IMap.EqualiltyMap(this, other); 31 | } 32 | 33 | public int CompareTo(IMap? other) 34 | { 35 | if (other is null) 36 | return 1; 37 | 38 | return IMap.CompareMap(this, other); 39 | } 40 | 41 | public int Hash { get; } 42 | public ConcreteGroup Domain { get; } 43 | 44 | public IEnumerable Kernel() 45 | { 46 | var n = G2.Neutral(); 47 | foreach (var e in map.Keys) 48 | { 49 | if (this[e].Equals(n)) 50 | yield return e; 51 | } 52 | } 53 | 54 | public IEnumerable Image() => map.Values; 55 | 56 | public T2 this[T1 index] => map[index]; 57 | 58 | public bool Equals(MapElt other) => IMap.EqualiltyMap(this, other); 59 | 60 | public int CompareTo(MapElt other) => IMap.CompareMap(this, other); 61 | 62 | public override int GetHashCode() => Hash; 63 | 64 | public override string ToString() 65 | { 66 | return map.AscendingByKey().GlueMap("; ", "{0}->[{1}]"); 67 | } 68 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/MapGroupBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures.CartesianProduct; 4 | 5 | namespace FastGoat.Structures.GenericGroup; 6 | 7 | public struct MapGroupBase : IGroup> where T1 : struct, IElt where T2 : struct, IElt 8 | { 9 | public MapGroupBase(ConcreteGroup G1, ConcreteGroup G2) 10 | { 11 | (this.G2, Domain) = (G2, G1); 12 | Hash = (G1.Count(), G2.Count()).GetHashCode(); 13 | Name = $"MapGroups({Domain},{this.G2})"; 14 | } 15 | 16 | public ConcreteGroup Domain { get; } 17 | public ConcreteGroup G2 { get; } 18 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 19 | 20 | IEnumerator IEnumerable.GetEnumerator() 21 | { 22 | return GetEnumerator(); 23 | } 24 | 25 | public bool Equals(IGroup, T2>>? other) => other?.Hash == Hash; 26 | 27 | public int Hash { get; } 28 | public string Name { get; } 29 | 30 | public MapElt this[params ValueType[] us] => throw new NotImplementedException(); 31 | 32 | public IEnumerable> GetElements() 33 | { 34 | yield return Neutral(); 35 | } 36 | 37 | public IEnumerable> GetGenerators() 38 | { 39 | yield return Neutral(); 40 | } 41 | 42 | public MapElt Neutral() 43 | { 44 | var nN = G2.Neutral(); 45 | var map = Domain.ToDictionary(g0 => g0, _ => nN); 46 | return new MapElt(Domain, G2, map); 47 | } 48 | 49 | public MapElt Invert(MapElt e) 50 | { 51 | var map = new Dictionary(); 52 | foreach (var v in Domain) 53 | map[v] = G2.Invert(e[v]); 54 | 55 | return new MapElt(Domain, G2, map); 56 | } 57 | 58 | public MapElt Op(MapElt e1, MapElt e2) 59 | { 60 | var map = new Dictionary(); 61 | foreach (var v in Domain) 62 | map[v] = G2.Op(e1[v], e2[v]); 63 | 64 | return new MapElt(Domain, G2, map); 65 | } 66 | 67 | public bool Equals(MapGroupBase other) => other.Hash == Hash; 68 | 69 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 70 | 71 | public override int GetHashCode() => Hash; 72 | public override string ToString() => Name; 73 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/OpGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public enum FGroupOp 6 | { 7 | Additive, 8 | Multiplicative 9 | } 10 | 11 | public class OpGroup : IGroup where K : struct, IFieldElt, IRingElt, IElt 12 | { 13 | private K neutral { get; } 14 | public FGroupOp FGroupOp { get; } 15 | public K[] PseudoGenerators { get; } 16 | 17 | public OpGroup(string name, K scalar, FGroupOp fGroupOp) 18 | { 19 | Name = name; 20 | neutral = fGroupOp == FGroupOp.Additive ? scalar.Zero : scalar.One; 21 | FGroupOp = fGroupOp; 22 | Hash = (name, neutral, fGroupOp).GetHashCode(); 23 | PseudoGenerators = new[] { scalar }; 24 | } 25 | 26 | public OpGroup(string name, K[] gens, FGroupOp fGroupOp) 27 | { 28 | if (gens.Length == 0) 29 | throw new GroupException(GroupExceptionType.GroupDef); 30 | var scalar = gens[0]; 31 | Name = name; 32 | neutral = fGroupOp == FGroupOp.Additive ? scalar.Zero : scalar.One; 33 | FGroupOp = fGroupOp; 34 | Hash = (name, neutral, fGroupOp).GetHashCode(); 35 | PseudoGenerators = gens.ToArray(); 36 | } 37 | 38 | public IEnumerator GetEnumerator() => GetElements().GetEnumerator(); 39 | 40 | IEnumerator IEnumerable.GetEnumerator() 41 | { 42 | return GetEnumerator(); 43 | } 44 | 45 | public bool Equals(IGroup? other) => other?.Hash == Hash; 46 | 47 | public int Hash { get; } 48 | public string Name { get; } 49 | 50 | public K this[params ValueType[] us] 51 | { 52 | get 53 | { 54 | if (us.Length != 1) 55 | throw new GroupException(GroupExceptionType.GroupDef); 56 | if (us[0] is int k) 57 | return FGroupOp == FGroupOp.Additive ? neutral + k : neutral * k; 58 | else 59 | throw new GroupException(GroupExceptionType.GroupDef); 60 | } 61 | } 62 | 63 | public IEnumerable GetElements() 64 | { 65 | yield return neutral; 66 | } 67 | 68 | public IEnumerable GetGenerators() => PseudoGenerators; 69 | 70 | public K Neutral() => neutral; 71 | 72 | public K Invert(K e) => FGroupOp == FGroupOp.Additive ? e.Opp() : e.Inv(); 73 | 74 | public K Op(K e1, K e2) => FGroupOp == FGroupOp.Additive ? e1.Add(e2) : e1.Mul(e2); 75 | public override int GetHashCode() => Hash; 76 | 77 | public override string ToString() => Name; 78 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/Quotient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.Structures.GenericGroup; 5 | 6 | public class Quotient : IGroup> where T : struct, IElt 7 | { 8 | public Quotient(ConcreteGroup grG, ConcreteGroup grH) 9 | { 10 | G = grG; 11 | H = grH; 12 | Hash = (G.Hash, G.Hash, "Quo").GetHashCode(); 13 | Name = $"{G.NameParenthesis()}/{H.NameParenthesis()}"; 14 | 15 | Ord = H.Count(); 16 | if (Ord < Group.GetStorageCapacity()) 17 | { 18 | InvertTable = new(2 * Ord); 19 | OpTable = new(2 * Ord * Ord); 20 | } 21 | else 22 | { 23 | InvertTable = new(); 24 | OpTable = new(); 25 | } 26 | 27 | Map = Group.Cosets(G, H); 28 | Elements = Map.Values.ToHashSet(); 29 | } 30 | 31 | private Dictionary> Map { get; } 32 | private HashSet> Elements { get; } 33 | public Coset GetRepresentative(T x) => Map[x]; 34 | public ConcreteGroup G { get; } 35 | public ConcreteGroup H { get; } 36 | private int Ord { get; } 37 | public Dictionary InvertTable { get; } 38 | public Dictionary<(T, T), T> OpTable { get; } 39 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 40 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 41 | public IEnumerable> GetElements() => Elements; 42 | 43 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 44 | 45 | public int Hash { get; } 46 | public string Name { get; } 47 | 48 | public Coset this[params ValueType[] us] => GetRepresentative(G[us]); 49 | 50 | public IEnumerable> GetGenerators() 51 | { 52 | yield return Neutral(); 53 | } 54 | 55 | public Coset Neutral() => GetRepresentative(H.Neutral()); 56 | 57 | public Coset Invert(Coset e) 58 | { 59 | if (Ord >= Group.GetStorageCapacity()) 60 | return GetRepresentative(H.Invert(e.X)); 61 | 62 | if (InvertTable.TryGetValue(e.X, out var r)) 63 | return GetRepresentative(r); 64 | 65 | var ei = InvertTable[e.X] = H.Invert(e.X); 66 | return GetRepresentative(ei); 67 | } 68 | 69 | public Coset Op(Coset e1, Coset e2) 70 | { 71 | if (Ord >= Group.GetStorageCapacity()) 72 | return GetRepresentative(H.Op(e1.X, e2.X)); 73 | 74 | var e12 = (e1.X, e2.X); 75 | if (OpTable.TryGetValue(e12, out var r)) 76 | return GetRepresentative(r); 77 | 78 | var e3 = OpTable[e12] = H.Op(e1.X, e2.X); 79 | return GetRepresentative(e3); 80 | } 81 | 82 | public override int GetHashCode() => Hash; 83 | public override string ToString() => Name; 84 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GenericGroup/SemiDirectProduct.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.CartesianProduct; 2 | 3 | namespace FastGoat.Structures.GenericGroup; 4 | 5 | public class SemiDirectProduct : ConcreteGroup> 6 | where T1 : struct, IElt where T2 : struct, IElt 7 | { 8 | public Homomorphism> Theta { get; } 9 | public ConcreteGroup N { get; } 10 | public ConcreteGroup G { get; } 11 | public ConcreteGroup> Ncan { get; } 12 | public ConcreteGroup> Gcan { get; } 13 | public Dictionary, Ep2> InvertTable { get; } 14 | public Dictionary<(Ep2, Ep2), Ep2> OpTable { get; } 15 | 16 | public SemiDirectProduct(string name, ConcreteGroup n, Homomorphism> theta, 17 | ConcreteGroup g) : base(name, Product.Group(n, g), true) 18 | { 19 | G = g; 20 | N = n; 21 | Name = !string.IsNullOrEmpty(name) ? name : $"{n.NameParenthesis()} x: {g.NameParenthesis()}"; 22 | 23 | Theta = theta; 24 | List> generators = new List>(); 25 | foreach (var e in G.GetGenerators()) 26 | generators.Add(Product.Elt(N.Neutral(), e)); 27 | 28 | foreach (var e in N.GetGenerators()) 29 | generators.Add(Product.Elt(e, G.Neutral())); 30 | 31 | Ord = N.Count() * G.Count(); 32 | if (Ord < Group.GetStorageCapacity()) 33 | { 34 | InvertTable = new(2 * Ord); 35 | OpTable = new(2 * Ord * Ord); 36 | } 37 | else 38 | { 39 | InvertTable = new(); 40 | OpTable = new(); 41 | } 42 | 43 | var (tmpElements, uniqueGenerators) = Group.UniqueGenerators(this, generators.ToArray()); 44 | PseudoGenerators = new(generators.ToArray()); 45 | Elements = tmpElements; 46 | ElementsOrders = Group.ElementsOrders(this, Elements); 47 | GroupType = Group.IsCommutative(this, PseudoGenerators) 48 | ? GroupType.AbelianGroup 49 | : GroupType.NonAbelianGroup; 50 | 51 | Ncan = Group.Generate(N.Name, this, n.Select(e => Product.Elt(e, G.Neutral())).ToArray()); 52 | Gcan = Group.Generate(G.Name, this, g.Select(e => Product.Elt(N.Neutral(), e)).ToArray()); 53 | } 54 | 55 | private int Ord { get; } 56 | public bool IsFaithFull() => Theta.Kernel().Count() == 1; 57 | 58 | public Ep2 Act(T1 en, T2 eg) 59 | { 60 | if (!N.Contains(en) || !G.Contains(eg)) 61 | throw new GroupException(GroupExceptionType.BaseGroup); 62 | 63 | return Product.Elt(Theta[eg][en], eg); 64 | } 65 | 66 | public override Ep2 Invert(Ep2 e) 67 | { 68 | if (Ord >= Group.GetStorageCapacity()) 69 | { 70 | var gi = G.Invert(e.E2); 71 | var xi = N.Invert(e.E1); 72 | return Product.Elt(Theta[gi][xi], gi); 73 | } 74 | else 75 | { 76 | if (InvertTable.TryGetValue(e, out var r)) 77 | return r; 78 | 79 | var gi = G.Invert(e.E2); 80 | var xi = N.Invert(e.E1); 81 | var ei = InvertTable[e] = Product.Elt(Theta[gi][xi], gi); 82 | return ei; 83 | } 84 | } 85 | 86 | public override Ep2 Op(Ep2 e1, Ep2 e2) 87 | { 88 | if (Ord >= Group.GetStorageCapacity()) 89 | { 90 | var n = N.Op(e1.E1, Theta[e1.E2][e2.E1]); 91 | var g = G.Op(e1.E2, e2.E2); 92 | return Product.Elt(n, g); 93 | } 94 | else 95 | { 96 | var e12 = (e1, e2); 97 | if (OpTable.TryGetValue(e12, out var r)) 98 | return r; 99 | 100 | var n = N.Op(e1.E1, Theta[e1.E2][e2.E1]); 101 | var g = G.Op(e1.E2, e2.E2); 102 | var e3 = OpTable[e12] = Product.Elt(n, g); 103 | return e3; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /FastGoat/Structures/GroupException.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures; 2 | 3 | public enum GroupExceptionType 4 | { 5 | GroupDef, 6 | BaseGroup, 7 | NotSubGroup, 8 | NotNormal, 9 | OnlyAbelianGroups, 10 | SemiDirectProductDontExist, 11 | NotIrreductiblePolynom 12 | } 13 | 14 | public class GroupException : Exception 15 | { 16 | public GroupException(GroupExceptionType type) : base(ErrMsg(type)) 17 | { 18 | } 19 | 20 | private static string ErrMsg(GroupExceptionType type) 21 | { 22 | return type switch 23 | { 24 | GroupExceptionType.GroupDef => "Group or Element cannot be created", 25 | GroupExceptionType.BaseGroup => "Groups or Elements do not belong to the base group", 26 | GroupExceptionType.NotSubGroup => "Not a valid subgroup", 27 | GroupExceptionType.NotNormal => "Not a normal subgroup", 28 | GroupExceptionType.OnlyAbelianGroups => "Only abelians groups are allowed for invariants decomposition", 29 | GroupExceptionType.SemiDirectProductDontExist => "Semi-direct product does not exists", 30 | GroupExceptionType.NotIrreductiblePolynom => "Polynom must be monic irreductible", 31 | _ => "Unexpected error" 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /FastGoat/Structures/GroupType.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures; 2 | 3 | [Flags] 4 | public enum GroupType 5 | { 6 | AbelianGroup = 0, 7 | NonAbelianGroup = 1 8 | } -------------------------------------------------------------------------------- /FastGoat/Structures/ICoset.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.GenericGroup; 2 | 3 | namespace FastGoat.Structures; 4 | 5 | public interface ICoset : IEnumerable, IElt where T : struct, IElt where U : struct, IElt 6 | { 7 | CosetType CosetType { get; } 8 | T X { get; } 9 | ConcreteGroup G { get; } 10 | ConcreteGroup H { get; } 11 | } -------------------------------------------------------------------------------- /FastGoat/Structures/IElt.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures; 2 | 3 | public interface IElt : IEquatable, IComparable where T : IElt 4 | { 5 | int Hash { get; } 6 | } -------------------------------------------------------------------------------- /FastGoat/Structures/IGmoduleNElt.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures; 2 | 3 | public interface IGmoduleNElt : IEquatable, IComparable 4 | where N : struct, IElt 5 | where G : struct, IElt 6 | where T : struct, IElt, IGmoduleNElt 7 | { 8 | T Add(T n); 9 | T Sub(T n); 10 | T Opp(); 11 | T Act(int k); 12 | 13 | T Act(G a); 14 | 15 | static abstract T operator +(T a, T b); 16 | static abstract T operator -(T a, T b); 17 | static abstract T operator -(T a); 18 | static abstract T operator *(G a, T b); 19 | static abstract T operator *(int k, T b); 20 | } -------------------------------------------------------------------------------- /FastGoat/Structures/IGroup.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures; 2 | 3 | public interface IGroup : IEnumerable, IEquatable> where T : IElt 4 | { 5 | int Hash { get; } 6 | string Name { get; } 7 | T this[params ValueType[] us] { get; } 8 | IEnumerable GetElements(); 9 | IEnumerable GetGenerators(); 10 | T Neutral(); 11 | T Invert(T e); 12 | T Op(T e1, T e2); 13 | 14 | static virtual bool IsFiniteGroup() => true; 15 | } -------------------------------------------------------------------------------- /FastGoat/Structures/IMap.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures.GenericGroup; 3 | 4 | namespace FastGoat.Structures; 5 | 6 | public interface IMap : IElt> where T1 : struct, IElt where T2 : struct, IElt 7 | { 8 | ConcreteGroup Domain { get; } 9 | IEnumerable Kernel(); 10 | IEnumerable Image(); 11 | T2 this[T1 index] { get; } 12 | 13 | public static bool EqualiltyMap(IMap map1, IMap map2) 14 | { 15 | if (!map1.Domain.SetEquals(map2.Domain)) 16 | return false; 17 | 18 | return map1.Domain.All(e => map1[e].Equals(map2[e])); 19 | } 20 | 21 | public static int CompareMap(IMap map1, IMap map2) 22 | { 23 | if (!map1.Domain.SetEquals(map2.Domain)) 24 | return 1; 25 | 26 | foreach (var e in map1.Domain.Ascending()) 27 | { 28 | var compE = map1[e].CompareTo(map2[e]); 29 | if (compE != 0) 30 | return compE; 31 | } 32 | 33 | return 0; 34 | } 35 | } -------------------------------------------------------------------------------- /FastGoat/Structures/IRingFieldVspaceElt.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Numerics; 3 | 4 | namespace FastGoat.Structures; 5 | 6 | public interface IRingElt : IEquatable, IComparable where T : IElt, IRingElt 7 | { 8 | bool IsZero(); 9 | T Zero { get; } 10 | T One { get; } 11 | T Add(T e); 12 | T Sub(T e); 13 | T Opp(); 14 | T Mul(T e); 15 | (T quo, T rem) Div(T e); 16 | T Mul(int k); 17 | T Pow(int k); 18 | static abstract T operator +(T a, T b); 19 | static abstract T operator +(int a, T b); 20 | static abstract T operator +(T a, int b); 21 | static abstract T operator -(T a); 22 | static abstract T operator -(T a, T b); 23 | static abstract T operator -(int a, T b); 24 | static abstract T operator -(T a, int b); 25 | static abstract T operator *(T a, T b); 26 | static abstract T operator *(int a, T b); 27 | static abstract T operator *(T a, int b); 28 | static abstract T operator /(T a, T b); 29 | static abstract T operator /(T a, int b); 30 | } 31 | 32 | public interface IFieldElt : IEquatable, IComparable where T : IElt, IRingElt, IFieldElt 33 | { 34 | int P { get; } 35 | T Inv(); 36 | bool Invertible(); 37 | static abstract T operator /(int a, T b); 38 | static abstract double Abs(T t); 39 | static abstract bool IsValuedField { get; } 40 | } 41 | 42 | public interface IModuleElt : IEquatable, IComparable 43 | where T : IElt, IRingElt, IModuleElt 44 | where K : IElt, IRingElt 45 | { 46 | K KZero { get; } 47 | K KOne { get; } 48 | T KMul(K k); 49 | static abstract T operator +(T a, K b); 50 | static abstract T operator +(K a, T b); 51 | static abstract T operator -(T a, K b); 52 | static abstract T operator -(K a, T b); 53 | static abstract T operator *(T a, K b); 54 | static abstract T operator *(K a, T b); 55 | } 56 | 57 | public interface IVsElt : IEquatable, IComparable 58 | where T : IElt, IRingElt, IModuleElt, IVsElt 59 | where K : IElt, IRingElt, IFieldElt 60 | { 61 | static abstract T operator /(T a, K b); 62 | } 63 | 64 | public interface IFloatElt : IEquatable, IComparable where K : IElt, IRingElt, IFieldElt, IFloatElt 65 | { 66 | public K RoundEven { get; } 67 | public K Absolute { get; } 68 | public K Absolute2 { get; } 69 | public K Conj { get; } 70 | public int Sign { get; } 71 | public double ToDouble { get; } 72 | public static abstract bool IsComplex { get; } 73 | public static abstract K Pi(int o = 50); 74 | public static abstract K Sqrt(K r); 75 | public static abstract K NthRoot(K r, int n); 76 | } 77 | 78 | public interface IFixedPrecisionElt : IEquatable, IComparable 79 | where K : struct, IElt, IRingElt, IFieldElt, IFloatElt, IFixedPrecisionElt 80 | { 81 | static abstract K From(T e) where T : IElt, IRingElt, IFieldElt, IFloatElt; 82 | static abstract int Digits { get; } 83 | static abstract bool operator ==(K a, K b); 84 | static abstract bool operator !=(K a, K b); 85 | static abstract bool operator <(K a, K b); 86 | static abstract bool operator >(K a, K b); 87 | static abstract bool operator <=(K a, K b); 88 | static abstract bool operator >=(K a, K b); 89 | static abstract K Min(K a, K b); 90 | static abstract K Max(K a, K b); 91 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Naming/ANameElt.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using FastGoat.Structures.GenericGroup; 3 | 4 | namespace FastGoat.Structures.Naming; 5 | 6 | public abstract class ANameElt : IElt 7 | { 8 | [Flags] 9 | public enum DecompType 10 | { 11 | Abelian = 0, 12 | DirectProduct = 1, 13 | SemiDirectProduct = 2, 14 | Extension = 3, 15 | SimpleNonAbelian = 4 16 | } 17 | 18 | [Flags] 19 | public enum NodeType 20 | { 21 | Leaf = 0, 22 | DirectProduct = 1, 23 | SemiDirectProduct = 2, 24 | Extension = 3 25 | } 26 | 27 | public BigInteger Weight { get; set; } 28 | public int Depth { get; set; } 29 | 30 | public ConcreteGroup? ContentGroup { get; set; } 31 | public NodeType ContentType { get; set; } 32 | public string Name { get; set; } = "C1"; 33 | public (int, string) LN => (Name.Length, Name); 34 | public int Hash => (ContentType, Name).GetHashCode(); 35 | public string NameParenthesis => Name.WithParenthesis(); 36 | public bool Equals(ANameElt? other) => other?.Name == Name; 37 | 38 | public bool IsExtension => ContentType == NodeType.Extension; 39 | 40 | public int CompareTo(ANameElt? other) 41 | { 42 | if (other is null) 43 | return 1; 44 | 45 | var compCTC = IsExtension.CompareTo(other.IsExtension); 46 | if (compCTC != 0) 47 | return compCTC; 48 | 49 | var compD = Depth.CompareTo(other.Depth); 50 | if (compD != 0) 51 | return compD; 52 | 53 | var compCT = ContentType.CompareTo(other.ContentType); 54 | if (compCT != 0) 55 | return compCT; 56 | 57 | var compW = Weight.CompareTo(other.Weight); 58 | if (compW != 0) 59 | return compW; 60 | 61 | return LN.CompareTo(other.LN); 62 | } 63 | 64 | public override int GetHashCode() => Hash; 65 | 66 | public override string ToString() => Name; 67 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Naming/DirectProductOp.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures.GenericGroup; 4 | 5 | namespace FastGoat.Structures.Naming; 6 | 7 | public class DirectProductOp : ANameElt 8 | { 9 | public ANameElt[] Elts { get; } 10 | 11 | public DirectProductOp(ANameElt lhs, ANameElt rhs, ConcreteGroup g) 12 | { 13 | ContentType = NodeType.DirectProduct; 14 | ContentGroup = g; 15 | if (lhs.ContentType == NodeType.DirectProduct && rhs.ContentType == NodeType.DirectProduct) 16 | Elts = ((DirectProductOp)lhs).Elts.Concat(((DirectProductOp)rhs).Elts).ToArray(); 17 | else if (lhs.ContentType == NodeType.DirectProduct) 18 | Elts = ((DirectProductOp)lhs).Elts.Append(rhs).ToArray(); 19 | else if (rhs.ContentType == NodeType.DirectProduct) 20 | Elts = ((DirectProductOp)rhs).Elts.Append(lhs).ToArray(); 21 | else 22 | Elts = new[] {lhs, rhs}; 23 | 24 | var abGens = Elts.Where(e => e.ContentGroup!.GroupType == GroupType.AbelianGroup) 25 | .SelectMany(e => e.ContentGroup!.GetGenerators()).Distinct().ToArray(); 26 | if (abGens.Length != 0) 27 | { 28 | var nab = Elts.Where(e => e.ContentGroup!.GroupType == GroupType.NonAbelianGroup).ToArray(); 29 | var ab = Group.Generate("Ab", g, abGens); 30 | var leaf = new Leaf(ab); 31 | Elts = nab.Prepend(leaf).ToArray(); 32 | } 33 | 34 | Elts = Elts.Order().ToArray(); 35 | Name = Elts.Select(e => e.NameParenthesis).Glue(" x "); 36 | Depth = 1 + Elts.Max(e => e.Depth); 37 | Weight = Elts.Max(e => e.Weight); 38 | } 39 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Naming/ExtensionOp.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.GenericGroup; 2 | 3 | namespace FastGoat.Structures.Naming; 4 | 5 | public class ExtensionOp : ANameElt 6 | { 7 | public ANameElt Lhs { get; } 8 | public ANameElt Rhs { get; } 9 | 10 | public ExtensionOp(ANameElt lhs, ANameElt rhs, ConcreteGroup g) 11 | { 12 | ContentGroup = g; 13 | ContentType = NodeType.Extension; 14 | (Lhs, Rhs) = (lhs, rhs); 15 | Name = $"{Lhs.NameParenthesis} . {Rhs.NameParenthesis}"; 16 | Depth = 1 + int.Max(Lhs.Depth, Rhs.Depth); 17 | Weight = Lhs.Weight * Rhs.Weight; 18 | } 19 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Naming/Leaf.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Text.RegularExpressions; 3 | using FastGoat.Commons; 4 | using FastGoat.Structures.GenericGroup; 5 | using FastGoat.Structures.Subgroups; 6 | 7 | namespace FastGoat.Structures.Naming; 8 | 9 | public class Leaf : ANameElt 10 | { 11 | public Leaf(AllSubgroups subgroups, DecompType decompType) 12 | { 13 | ContentGroup = subgroups.Parent; 14 | ContentType = NodeType.Leaf; 15 | Depth = 0; 16 | if (decompType == DecompType.Abelian) 17 | { 18 | var abType = Group.AbelianGroupType(ContentGroup); 19 | Name = abType.Glue(" x ", "C{0}"); 20 | Weight = abType.Length * 5 + 15; 21 | } 22 | else if (decompType == DecompType.SimpleNonAbelian) 23 | { 24 | Name = SimpleNonAbelians(ContentGroup); 25 | Weight = 30; 26 | } 27 | } 28 | 29 | public Leaf(ConcreteGroup g) 30 | { 31 | ContentGroup = g; 32 | if (g.GroupType == GroupType.NonAbelianGroup) 33 | throw new GroupException(GroupExceptionType.GroupDef); 34 | 35 | ContentType = NodeType.Leaf; 36 | var abType = Group.AbelianGroupType(ContentGroup); 37 | Name = abType.Glue(" x ", "C{0}"); 38 | Weight = abType.Length * 5 + 15; 39 | Depth = 0; 40 | } 41 | 42 | public Leaf(ConcreteGroup g, string name) 43 | { 44 | ContentGroup = g; 45 | ContentType = NodeType.Leaf; 46 | Name = name; 47 | Depth = 0; 48 | Weight = 30; 49 | } 50 | 51 | static string SimpleNonAbelians(ConcreteGroup G) 52 | { 53 | var og = G.Count(); 54 | if (og == 60) 55 | return "A5"; 56 | if (og == 168) 57 | return "SL(3,2)"; 58 | if (og == 360) 59 | return "A6"; 60 | if (og == 504) 61 | return "SL(2,8)"; 62 | if (og == 660) 63 | return "L2(11)"; 64 | if (og == 1092) 65 | return "L2(13)"; 66 | if (og == 2520) 67 | return "A7"; 68 | 69 | return G.Name; 70 | } 71 | 72 | public (string prefix, int[] coefs) LeafDetails() 73 | { 74 | if (ContentGroup!.GroupType == GroupType.AbelianGroup) 75 | return ("C", Group.AbelianGroupType(ContentGroup)); 76 | 77 | string regX = @"(Q|Dic|A|S|L2)(\d+)|(GL|SL)\((\d+),(\d+)\)"; 78 | var match = Regex.Match(Name, regX); 79 | var s1 = match.Groups["1"].Value; 80 | var s3 = match.Groups["3"].Value; 81 | if (string.IsNullOrEmpty(s3) && !string.IsNullOrEmpty(s1)) 82 | { 83 | var n = int.Parse(match.Groups["2"].Value); 84 | return (s1, new[] { n }); 85 | } 86 | else if (string.IsNullOrEmpty(s1) && !string.IsNullOrEmpty(s3)) 87 | { 88 | var n = int.Parse(match.Groups["4"].Value); 89 | var p = int.Parse(match.Groups["5"].Value); 90 | return (s3, new[] { n, p }); 91 | } 92 | 93 | throw new(); 94 | } 95 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Subgroups/GroupSubset.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Structures.GenericGroup; 3 | 4 | namespace FastGoat.Structures.Subgroups; 5 | 6 | public readonly struct GroupSubset(HashSet gens, HashSet content) 7 | : IEnumerable, IElt> where T : struct, IElt 8 | { 9 | public HashSet Generators => gens; 10 | public HashSet Elements => content; 11 | public int Count => content.Count; 12 | public bool Contains(T e) => content.Contains(e); 13 | public bool SuperSetOf(IEnumerable other) => content.IsSupersetOf(other); 14 | public bool SubSetOf(IEnumerable other) => content.IsSubsetOf(other); 15 | public bool SetEquals(IEnumerable other) => content.SetEquals(other); 16 | public bool Equals(GroupSubset other) => content.Count == other.Count && content.SetEquals(other.Elements); 17 | 18 | public int CompareTo(GroupSubset other) => Count.CompareTo(other.Count); 19 | 20 | private int IdHash => content.Order().Aggregate(1, (acc, e) => (acc, e.GetHashCode()).GetHashCode()); 21 | 22 | public int Hash => Count; 23 | public IEnumerator GetEnumerator() => content.GetEnumerator(); 24 | 25 | IEnumerator IEnumerable.GetEnumerator() 26 | { 27 | return GetEnumerator(); 28 | } 29 | 30 | public GroupSubset ToWElt() => 31 | new(Generators.Select(e => new WElt(e)).ToHashSet(), Elements.Select(e => new WElt(e)).ToHashSet()); 32 | 33 | public override int GetHashCode() => Hash; 34 | public override string ToString() => $"Set[{Count}]{IdHash}"; 35 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Subgroups/Serie.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.Subgroups; 4 | 5 | public struct Serie : IEquatable> where T : struct, IElt 6 | { 7 | public List> Content { get; } 8 | public int Placeholder { get; } 9 | public string SymbolNormal { get; } 10 | public SerieType SerieType { get; } 11 | public int Count => Content.Count; 12 | 13 | public Serie(List> serie, SerieType serieType, int digits, string symbolNormal = " ⊲ ") 14 | { 15 | SerieType = serieType; 16 | Content = serie; 17 | Placeholder = digits; 18 | SymbolNormal = symbolNormal; 19 | } 20 | 21 | public IEnumerable ContentName => Content.Select(s => s.Representative.Name); 22 | 23 | public bool IsRefinementOf(Serie serie) => ContentName.All(n => serie.ContentName.Contains(n)); 24 | 25 | public bool AddTo(HashSet> series) 26 | { 27 | var serie = this; 28 | if (series.Any(s => serie.IsRefinementOf(s))) 29 | return false; 30 | 31 | series.RemoveWhere(s => s.IsRefinementOf(serie)); 32 | return series.Add(serie); 33 | } 34 | 35 | public bool Equals(Serie other) => ContentName.SequenceEqual(other.ContentName); 36 | 37 | public override int GetHashCode() => Content.Count; 38 | 39 | public override string ToString() 40 | { 41 | var digits = Placeholder; 42 | var dash = Enumerable.Repeat('-', digits).Glue(); 43 | var fmt = $"{{0,-{digits}}}"; 44 | 45 | if (SerieType == SerieType.Serie) 46 | return Content.Select(s => s.Order == 1 ? "C1" : $"{s.FullName} {dash}".Substring(0, digits)).Glue("--> ", fmt).Trim(); 47 | 48 | return ContentName.Reverse().Glue(SymbolNormal, fmt).Trim(); 49 | } 50 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Subgroups/SerieType.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.Subgroups; 2 | 3 | public enum SerieType 4 | { 5 | Serie, Chief, Composition, Lower, Upper, Derived 6 | } -------------------------------------------------------------------------------- /FastGoat/Structures/Subgroups/SubGroupsInfos.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.Subgroups; 2 | 3 | public record SubGroupsInfos(int AllSubGr, int AllConjsCl, int AllNorms) : IComparable 4 | { 5 | public (int, int, int) ToTuples() => (AllSubGr, AllConjsCl, AllNorms); 6 | 7 | public int CompareTo(SubGroupsInfos? other) 8 | { 9 | if (other is null) 10 | return 1; 11 | 12 | return ToTuples().CompareTo(other.ToTuples()); 13 | } 14 | } -------------------------------------------------------------------------------- /FastGoat/Structures/VecSpace/GLnK.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.Structures.VecSpace; 5 | 6 | public readonly struct GLn : IGroup> where K : struct, IElt, IRingElt, IFieldElt 7 | { 8 | private KMatrix[] Generators { get; } 9 | private KMatrix idN { get; } 10 | public int N => idN.N; 11 | public K KZero => idN.KZero; 12 | 13 | public GLn(KMatrix e0, params KMatrix[] others) 14 | { 15 | Generators = others.Prepend(e0).ToArray(); 16 | idN = e0.One; 17 | var zero = idN.KZero; 18 | if (Generators.Select(m => m.Det).Any(d => d.Equals(zero))) 19 | throw new Exception($"|Det| == 0"); 20 | 21 | Hash = Generators.Aggregate(0, (acc, m) => (acc, m.Hash).GetHashCode()); 22 | Name = $"GL({idN.N}, {typeof(K)})"; 23 | } 24 | 25 | public GLn(string name, KMatrix e0, params KMatrix[] others) 26 | { 27 | Generators = others.Prepend(e0).ToArray(); 28 | idN = e0.One; 29 | var zero = idN.KZero; 30 | if (Generators.Select(m => m.Det).Any(d => d.Equals(zero))) 31 | throw new Exception($"|Det| == 0"); 32 | 33 | Hash = Generators.Aggregate(0, (acc, m) => (acc, m.Hash).GetHashCode()); 34 | Name = name; 35 | } 36 | 37 | public GLn(int n, K scalar) 38 | { 39 | idN = new KMatrix(scalar, n, n).One; 40 | Generators = new[] { idN }; 41 | Name = $"GL({idN.N}, {scalar})"; 42 | Hash = Name.GetHashCode(); 43 | } 44 | 45 | public GLn(string name, int n, K scalar) 46 | { 47 | idN = new KMatrix(scalar, n, n).One; 48 | Generators = new[] { idN }; 49 | Name = $"GL({idN.N}, {name})"; 50 | Hash = Name.GetHashCode(); 51 | } 52 | 53 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 54 | 55 | IEnumerator IEnumerable.GetEnumerator() 56 | { 57 | return GetEnumerator(); 58 | } 59 | 60 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 61 | 62 | public int Hash { get; } 63 | public string Name { get; } 64 | 65 | public static bool Contains(IGroup> g, KMatrix m) 66 | { 67 | var g0 = g is GLn ? (GLn)g : default; 68 | var kone = g0.idN.KOne; 69 | var det = m.Det; 70 | 71 | Console.WriteLine($"GLn"); 72 | return det.Equals(kone) || det.Equals(-kone); 73 | } 74 | 75 | public KMatrix this[params ValueType[] us] 76 | { 77 | get 78 | { 79 | if (us.Any(e => e is not int && e is not K)) 80 | throw new GroupException(GroupExceptionType.GroupDef); 81 | 82 | var kzero = idN.KZero; 83 | var kone = idN.KOne; 84 | var us0 = us.Select(e => e is int e0 ? e0 * kone : e is K e1 ? e1 : kzero).ToArray(); 85 | var m = new KMatrix(Ring.Matrix(N, us0)); 86 | var det = m.Det; 87 | 88 | if (K.IsValuedField) 89 | { 90 | if (Math.Abs(K.Abs(det)) < 1e-7) 91 | throw new GroupException(GroupExceptionType.GroupDef); 92 | } 93 | else if (det.Equals(kzero)) 94 | throw new GroupException(GroupExceptionType.GroupDef); 95 | 96 | return m; 97 | } 98 | } 99 | 100 | public IEnumerable> GetElements() 101 | { 102 | yield return idN; 103 | } 104 | 105 | public IEnumerable> GetGenerators() => Generators; 106 | 107 | public KMatrix Neutral() => idN; 108 | 109 | public KMatrix Invert(KMatrix e) => e.Inv(); 110 | 111 | public KMatrix Op(KMatrix e1, KMatrix e2) => e1 * e2; 112 | 113 | public override string ToString() => Name; 114 | public override int GetHashCode() => Hash; 115 | } -------------------------------------------------------------------------------- /FastGoat/Structures/VecSpace/KAut.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.VecSpace; 2 | 3 | public readonly struct KAut : IElt> where K : struct, IElt, IRingElt, IFieldElt 4 | { 5 | public KAutGroup KAutGroup { get; } 6 | public EPoly E { get; } 7 | public KAut Clone => new(E.Clone); 8 | 9 | public T Op(T a) where T : struct, IElt, IRingElt, IModuleElt, IVsElt => E.Poly.Substitute(a); 10 | 11 | public KAut(KAutGroup kaut, EPoly e) 12 | { 13 | if (!kaut.F.Equals(e.F)) 14 | throw new GroupException(GroupExceptionType.GroupDef); 15 | 16 | E = e; 17 | KAutGroup = kaut; 18 | var hash = e.Poly.Coefs.Aggregate(0, (acc, a) => (acc, a.Hash).GetHashCode()); 19 | Hash = (hash, KAutGroup.Hash).GetHashCode(); 20 | } 21 | 22 | public KAut(EPoly e) 23 | { 24 | E = e; 25 | KAutGroup = new KAutGroup(e.F); 26 | var hash = e.Poly.Coefs.Aggregate(0, (acc, a) => (acc, a.Hash).GetHashCode()); 27 | Hash = (hash, KAutGroup.Hash).GetHashCode(); 28 | } 29 | 30 | public bool Equals(KAut other) => E.Equals(other.E); 31 | 32 | public int CompareTo(KAut other) => E.CompareTo(other.E); 33 | 34 | public int Hash { get; } 35 | public override int GetHashCode() => Hash; 36 | public override string ToString() => E.ToString(); 37 | 38 | public static implicit operator KAut(EPoly e) => new(e); 39 | public static implicit operator EPoly(KAut e) => e.E; 40 | } -------------------------------------------------------------------------------- /FastGoat/Structures/VecSpace/KAutGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.Structures.VecSpace; 5 | 6 | public readonly struct KAutGroup : IGroup> where K : struct, IElt, IRingElt, IFieldElt 7 | { 8 | public KPoly F { get; } 9 | private EPoly X { get; } 10 | 11 | public KAutGroup(KPoly P) 12 | { 13 | F = P; 14 | Hash = P.Hash; 15 | Name = $"Q[{P.x}]/({P})"; 16 | X = new(F); 17 | } 18 | 19 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 20 | 21 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 22 | 23 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 24 | 25 | public int Hash { get; } 26 | public string Name { get; } 27 | 28 | public KAut KAut(EPoly e) => new(this, e); 29 | 30 | public KAut this[params ValueType[] us] 31 | { 32 | get 33 | { 34 | var cycles = us.Select(u => (Tuple2Array)u).ToArray(); 35 | if (cycles.Any(c => c.Table.Length == 0)) 36 | throw new GroupException(GroupExceptionType.GroupDef); 37 | 38 | var f = F; 39 | var one = F.KOne; 40 | if (cycles.All(c => c.Table.Length == 1) && cycles.Length == F.Degree + 1) 41 | { 42 | var coefs = cycles.SelectMany(c => c.Table).Select(c => c * one).ToArray(); 43 | var e0 = new EPoly(F, new KPoly(F.x, F.KZero, coefs)); 44 | return new(this, e0); 45 | } 46 | 47 | var polys = cycles.Select(c => c.Table.Select(e => e * one).ToArray()) 48 | .Select(coefs => new EPoly(f, new KPoly(f.x, f.KZero, coefs))).ToArray(); 49 | 50 | var e1 = polys.Aggregate(X, (acc, f0) => acc.Substitute(f0)); 51 | return new(this, e1); 52 | } 53 | } 54 | 55 | public IEnumerable> GetElements() 56 | { 57 | yield return Neutral(); 58 | } 59 | 60 | public IEnumerable> GetGenerators() 61 | { 62 | yield return new(this, X); 63 | } 64 | 65 | public KAut Neutral() => new(this, X); 66 | 67 | public KAut Invert(KAut e) 68 | { 69 | var n = e.E.X; 70 | var tmp0 = e.E.Clone; 71 | EPoly tmp1; 72 | do 73 | { 74 | tmp1 = tmp0.Clone; 75 | tmp0 = e.E.Substitute(tmp1); 76 | } while (!tmp0.Equals(n)); 77 | 78 | return new(this, tmp1); 79 | } 80 | 81 | public KAut Op(KAut e1, KAut e2) => new(this, e1.Op(e2.E)); 82 | public override int GetHashCode() => Hash; 83 | public override string ToString() => Name; 84 | } -------------------------------------------------------------------------------- /FastGoat/Structures/VecSpace/PolynomialBasis.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.Structures.VecSpace; 4 | 5 | public readonly struct PolynomialBasis : IElt> 6 | where K : struct, IElt, IRingElt, IFieldElt 7 | where T : struct, IElt 8 | { 9 | public Polynomial[] Basis { get; } 10 | public K[] LC { get; } 11 | public Monom[] LM { get; } 12 | public Polynomial[] LT { get; } 13 | public Indeterminates Indeterminates { get; } 14 | 15 | public PolynomialBasis() 16 | { 17 | throw new ArgumentException(); 18 | } 19 | 20 | public PolynomialBasis(Indeterminates indeterminates, params Polynomial[] basis) 21 | { 22 | if (basis.Any(p => !p.Indeterminates.Equals(indeterminates))) 23 | throw new(); 24 | 25 | Indeterminates = indeterminates; 26 | Basis = basis; 27 | var n = basis.Length; 28 | LC = new K[n]; 29 | LM = new Monom[n]; 30 | LT = new Polynomial[n]; 31 | Hash = 0; 32 | for (int i = 0; i < n; ++i) 33 | { 34 | var f = Basis[i]; 35 | if (!f.Indeterminates.Equals(Indeterminates)) 36 | throw new ArgumentException(); 37 | 38 | (LC[i], LM[i], LT[i]) = f.LeadingDetails; 39 | Hash = (Hash, f.Hash).GetHashCode(); 40 | } 41 | } 42 | 43 | public PolynomialBasis(params Polynomial[] basis) : this(basis[0].Indeterminates, basis) 44 | { 45 | } 46 | 47 | public int Hash { get; } 48 | 49 | public Polynomial Rem(Polynomial f) 50 | { 51 | var f0 = f; 52 | foreach (var p in Basis) 53 | f0 = f0.Div(p).rem; 54 | 55 | return f0; 56 | } 57 | 58 | public bool Equals(PolynomialBasis other) => Basis.SequenceEqual(other.Basis); 59 | 60 | public int CompareTo(PolynomialBasis other) => Basis.SequenceCompareTo(other.Basis); 61 | 62 | public override int GetHashCode() => Hash; 63 | public override string ToString() => $"[{Basis.Glue("; ")}]"; 64 | } -------------------------------------------------------------------------------- /FastGoat/Structures/VecSpace/Xi.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.Structures.VecSpace; 2 | 3 | public readonly struct Xi : IElt 4 | { 5 | public string xi { get; } 6 | 7 | public Xi() 8 | { 9 | xi = "X"; 10 | Hash = xi.GetHashCode(); 11 | } 12 | 13 | public Xi(int i) 14 | { 15 | var c = (char)('a' + i); 16 | if (!char.IsLetter(c)) 17 | throw new ArgumentException(); 18 | 19 | xi = ((char)c).ToString(); 20 | Hash = xi.GetHashCode(); 21 | } 22 | 23 | public Xi(char c) 24 | { 25 | if (!char.IsLetter(c)) 26 | throw new ArgumentException(); 27 | 28 | xi = c.ToString(); 29 | Hash = xi.GetHashCode(); 30 | } 31 | 32 | public Xi(string expr) 33 | { 34 | if (expr.Length == 0) 35 | throw new ArgumentException(); 36 | 37 | xi = expr; 38 | Hash = xi.GetHashCode(); 39 | } 40 | 41 | public bool Equals(Xi other) => Hash == other.Hash; 42 | 43 | public int CompareTo(Xi other) => String.Compare(xi, other.xi, StringComparison.Ordinal); 44 | 45 | public override int GetHashCode() => Hash; 46 | public override string ToString() => xi; 47 | public int Hash { get; } 48 | 49 | public static implicit operator Xi(string s) => new(s); 50 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Characters/AddCharacterState.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.UserGroup.Characters; 2 | 3 | public enum AddCharacterState 4 | { 5 | Rejected, 6 | NotOrth, 7 | TableFull, 8 | NotIrr, 9 | Done 10 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/DatabaseSmallGroups/IdGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using FastGoat.Structures.GenericGroup; 3 | using FastGoat.Structures.Subgroups; 4 | 5 | namespace FastGoat.UserGroup.DatabaseSmallGroups; 6 | 7 | public readonly struct IdGroup : IEquatable, IComparable 8 | { 9 | public int Order { get; } 10 | public int No { get; } 11 | 12 | public string Name { get; } 13 | 14 | public string Txt { get; } 15 | public SubGroupsInfos Infos { get; } 16 | 17 | private const string reg = @"\((\d*),(\d*)\);(.*);\((\d*),(\d*),(\d*)\)"; 18 | 19 | public IdGroup(string txt) 20 | { 21 | Txt = txt; 22 | 23 | Match m = Regex.Matches(txt, reg)[0]; 24 | var (idG, noG, nameG) = (m.Groups[1], m.Groups[2], m.Groups[3]); 25 | var (allSubGrG, allConjsClG, allNormsG) = (m.Groups[4], m.Groups[5], m.Groups[6]); 26 | 27 | (Order, No) = (int.Parse(idG.Value), int.Parse(noG.Value)); 28 | Name = nameG.Value; 29 | Infos = new SubGroupsInfos(int.Parse(allSubGrG.Value), int.Parse(allConjsClG.Value), int.Parse(allNormsG.Value)); 30 | } 31 | 32 | public string FullName => $"SmallGroup({Order},{No}) Name:{Name}"; 33 | 34 | public void Show() 35 | { 36 | Console.WriteLine($"Txt:{Txt}"); 37 | Console.WriteLine(FullName); 38 | Console.WriteLine(Infos); 39 | Console.WriteLine(); 40 | } 41 | 42 | public bool Equals(IdGroup other) => string.Equals(Txt, other.Txt); 43 | 44 | public int CompareTo(IdGroup other) => (Id: Order, No).CompareTo((other.Order, other.No)); 45 | 46 | public override string ToString() => Txt; 47 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/EllCurve/EllDB.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.UserGroup.EllCurve; 5 | 6 | public record EllDB(string name, BigInteger conductor, int rank, int[] torsType, BigInteger[] model) 7 | { 8 | public int ordTors => torsType.Aggregate((ai, aj) => ai * aj); 9 | 10 | public override string ToString() => $"[{model.Glue(", ")}]; {name}; {conductor}; ({rank}) x [{torsType.Glue(", ")}]"; 11 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/EllCurve/EllPt.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | 3 | namespace FastGoat.UserGroup.EllCurve; 4 | 5 | public readonly struct EllPt : IElt> where T : struct, IElt, IRingElt, IFieldElt 6 | { 7 | public T X { get; } 8 | public T Y { get; } 9 | 10 | public int Hash { get; } 11 | public bool IsO { get; } 12 | 13 | public EllPt() 14 | { 15 | IsO = true; 16 | Hash = (IsO, X, Y).GetHashCode(); 17 | } 18 | 19 | public EllPt(T x, T y) 20 | { 21 | IsO = false; 22 | (X, Y) = (x, y); 23 | Hash = (IsO, X, Y).GetHashCode(); 24 | } 25 | 26 | public bool Equals(EllPt other) 27 | { 28 | if ((IsO && !other.IsO) || (!IsO && other.IsO)) 29 | return false; 30 | 31 | return (IsO && other.IsO) || ((X - other.X).IsZero() && (Y - other.Y).IsZero()); 32 | } 33 | 34 | public int CompareTo(EllPt other) 35 | { 36 | if (Equals(other)) 37 | return 0; 38 | 39 | if (IsO) 40 | return -1; 41 | 42 | if (other.IsO) 43 | return 1; 44 | 45 | return (X, Y).CompareTo((other.X, other.Y)); 46 | } 47 | 48 | public override int GetHashCode() => Hash; 49 | 50 | public void Deconstruct(out T x, out T y) 51 | { 52 | if (IsO) 53 | throw new GroupException(GroupExceptionType.GroupDef); 54 | 55 | (x, y) = (X, Y); 56 | } 57 | 58 | public override string ToString() 59 | { 60 | return IsO ? "O" : $"({X}, {Y})"; 61 | } 62 | 63 | public static implicit operator EllPt((T x, T y) P) => new(P.x, P.y); 64 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/EllCurve/IndTriVar.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.VecSpace; 2 | 3 | namespace FastGoat.UserGroup.EllCurve; 4 | 5 | public class IndTriVar 6 | { 7 | public MonomOrder MonomOrder { get; } = MonomOrder.Lex; 8 | public string X1 { get; } = "X"; 9 | public string X2 { get; } = "Y"; 10 | public string X3 { get; } = "Z"; 11 | private int Hash { get; } 12 | 13 | public IndTriVar() 14 | { 15 | Hash = (MonomOrder, X1, X2, X3).GetHashCode(); 16 | } 17 | 18 | public IndTriVar(MonomOrder monomOrder) 19 | { 20 | MonomOrder = monomOrder; 21 | Hash = (MonomOrder, X1, X2, X3).GetHashCode(); 22 | } 23 | 24 | public IndTriVar(MonomOrder monomOrder, string x, string y, string z) 25 | { 26 | MonomOrder = monomOrder; 27 | (X1, X2, X3) = (x, y, z); 28 | Hash = (MonomOrder, X1, X2, X3).GetHashCode(); 29 | } 30 | 31 | public Comparer GetComparer() 32 | { 33 | return MonomOrder switch 34 | { 35 | MonomOrder.GrLex => comparerGrLex, 36 | MonomOrder.GrevLex => comparerGrevLex, 37 | _ => comparerLex 38 | }; 39 | } 40 | 41 | public override int GetHashCode() => Hash; 42 | public override string ToString() => $"[Order={MonomOrder} X1={X1} X2={X2} X3={X3}]"; 43 | 44 | static IndTriVar() 45 | { 46 | comparerLex = Comparer.Create((a, b) => a.CompareTo(b)); 47 | comparerGrLex = Comparer.Create( 48 | (a, b) => 49 | { 50 | var compDeg = a.Degree.CompareTo(b.Degree); 51 | if (compDeg != 0) 52 | return compDeg; 53 | 54 | return a.CompareTo(b); 55 | }); 56 | comparerGrevLex = Comparer.Create( 57 | (a, b) => 58 | { 59 | var compDeg = a.Degree.CompareTo(b.Degree); 60 | if (compDeg != 0) 61 | return compDeg; 62 | 63 | return -(a.CompareTo(b)); 64 | }); 65 | } 66 | 67 | private static Comparer comparerLex { get; } 68 | private static Comparer comparerGrLex { get; } 69 | private static Comparer comparerGrevLex { get; } 70 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/EllCurve/TateAlgo.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.UserGroup.EllCurve; 2 | 3 | public record TateAlgo(int p, int n, string kp, int fp, int cp); -------------------------------------------------------------------------------- /FastGoat/UserGroup/EllCurve/TriVar.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.UserGroup.EllCurve; 5 | 6 | public readonly struct TriVar : IElt 7 | { 8 | public TriVar() 9 | { 10 | (X3, X2, X1) = (0, 0, 0); 11 | Hash = (X3, X2, X1).GetHashCode(); 12 | } 13 | 14 | public TriVar(int x3, int x2, int x1) 15 | { 16 | (X3, X2, X1) = (x3, x2, x1); 17 | Hash = (X3, X2, X1).GetHashCode(); 18 | } 19 | 20 | public int X3 { get; } 21 | public int X2 { get; } 22 | public int X1 { get; } 23 | public int Degree => X3 + X2 + X1; 24 | public int Hash { get; } 25 | public bool IsOne() => X3 == 0 && X2 == 0 && X1 == 0; 26 | public TriVar Mul(TriVar e) => new(X3 + e.X3, X2 + e.X2, X1 + e.X1); 27 | public bool Equals(TriVar other) => X3 == other.X3 && X2 == other.X2 && X1 == other.X1; 28 | public int CompareTo(TriVar other) => (X3, X2, X1).CompareTo((other.X3, other.X2, other.X1)); 29 | public override int GetHashCode() => Hash; 30 | public override string ToString() => $"{(X3, X2, X1)}"; 31 | 32 | public void Deconstruct(out int x3, out int x2, out int x1) 33 | { 34 | (x3, x2, x1) = (X3, X2, X1); 35 | } 36 | 37 | public int this[int index] 38 | { 39 | get 40 | { 41 | return index switch 42 | { 43 | 3 => X3, 44 | 2 => X2, 45 | _ => X1 46 | }; 47 | } 48 | } 49 | 50 | public TriVar Set(int idx, int v) 51 | { 52 | return idx switch 53 | { 54 | 3 => new(v, X2, X1), 55 | 2 => new(X3, v, X1), 56 | _ => new(X3, X2, v), 57 | }; 58 | } 59 | 60 | public TriVar GetX3() => new(X3, 0, 0); 61 | public TriVar GetX2() => new(0, X2, 0); 62 | public TriVar GetX1() => new(0, 0, X1); 63 | public TriVar GetX3X2() => new(X3, X2, 0); 64 | public TriVar GetX3X1() => new(X3, 0, X1); 65 | public TriVar GetX2X1() => new(0, X2, X1); 66 | 67 | public static (TriVar pa, TriVar pb) Reduce(TriVar a, TriVar b) 68 | { 69 | int pax3 = 0, pax2 = 0, pax1 = 0; 70 | int pbx3 = 0, pbx2 = 0, pbx1 = 0; 71 | 72 | var mx3 = int.Max(a.X3, b.X3); 73 | if (mx3 != 0 && a.X3 != b.X3) 74 | { 75 | if (mx3 == b.X3) 76 | pax3 = mx3 - a.X3; 77 | else 78 | pbx3 = mx3 - b.X3; 79 | } 80 | 81 | var mx2 = int.Max(a.X2, b.X2); 82 | if (mx2 != 0 && a.X2 != b.X2) 83 | { 84 | if (mx2 == b.X2) 85 | pax2 = mx2 - a.X2; 86 | else 87 | pbx2 = mx2 - b.X2; 88 | } 89 | 90 | var mx1 = int.Max(a.X1, b.X1); 91 | if (mx1 != 0 && a.X1 != b.X1) 92 | { 93 | if (mx1 == b.X1) 94 | pax1 = mx1 - a.X1; 95 | else 96 | pbx1 = mx1 - b.X1; 97 | } 98 | 99 | return ((pax3, pax2, pax1), (pbx3, pbx2, pbx1)); 100 | } 101 | 102 | public static implicit operator TriVar((int x3, int x2, int x1) e) => new(e.x3, e.x2, e.x1); 103 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/GModuleN/SysReduction.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.VecSpace; 2 | using FastGoat.UserGroup.Integers; 3 | 4 | namespace FastGoat.UserGroup.GModuleN; 5 | 6 | public record SysReduction(Polynomial eq, 7 | int order, 8 | Xi xi, 9 | Polynomial substitutionExpr, 10 | int mod); -------------------------------------------------------------------------------- /FastGoat/UserGroup/GModuleN/SysSolution.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | 3 | namespace FastGoat.UserGroup.GModuleN; 4 | 5 | public record SysSolution(int total, List sreds, CrMap allMaps) 6 | where Tg : struct, IElt 7 | where Tn : struct, IElt; -------------------------------------------------------------------------------- /FastGoat/UserGroup/Integers/Cn.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.Structures.GenericGroup; 3 | 4 | namespace FastGoat.UserGroup.Integers; 5 | 6 | public class Cn : ConcreteGroup 7 | { 8 | public Cn(int n) : base($"C{n}", new Zn(n), new[] { new Zn(n)[1] }) 9 | { 10 | Hash = (BaseGroup.Hash, "Cn").GetHashCode(); 11 | } 12 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Integers/Un.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.Structures.GenericGroup; 4 | using FastGoat.UserGroup.Padic; 5 | 6 | namespace FastGoat.UserGroup.Integers; 7 | 8 | public class Un : ConcreteGroup> 9 | { 10 | public static ZnInt FirstGen(int p) => new Un(p).GetGenerators().First()[new ZnInt(p, 1)]; 11 | public static ZnBInt FirstGenZb(int p) => FirstGen(p).K * ZnBInt.ZnZero(p).One; 12 | public Cn Cn { get; } 13 | 14 | public Un(int n) : base($"U{n}", Group.AutBase(new Cn(n)), true) 15 | { 16 | var autCn = (AutomorphismGroup)BaseGroup; 17 | Cn = (Cn)autCn.G; 18 | var elements = new List>(); 19 | for (int k = 1; k < n; ++k) 20 | { 21 | if (IntExt.Gcd(k, n) != 1) 22 | continue; 23 | 24 | var ak = autCn[(Cn[1], Cn[k])]; 25 | elements.Add(ak); 26 | } 27 | 28 | Hash = (BaseGroup.Hash, "Un").GetHashCode(); 29 | Elements = elements.ToHashSet(); 30 | ElementsOrders = Group.ElementsOrders(autCn, Elements); 31 | var (tmpElements, uniqueGenerators) = Group.UniqueGenerators(this, Elements.ToArray()); 32 | PseudoGenerators = new(uniqueGenerators); 33 | GroupType = Group.IsCommutative(autCn, PseudoGenerators) ? GroupType.AbelianGroup : GroupType.NonAbelianGroup; 34 | } 35 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Integers/Zn.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.UserGroup.Integers; 5 | 6 | public readonly struct Zn : IGroup 7 | { 8 | public int Mod { get; } 9 | public string Name { get; } 10 | public string Fmt { get; } 11 | 12 | public Zn(int mod) 13 | { 14 | if (mod < 1) 15 | throw new GroupException(GroupExceptionType.GroupDef); 16 | 17 | Mod = mod; 18 | Name = $"Z{mod}"; 19 | var digits = $"{Mod - 1}".Length; 20 | Fmt = $"{{0,{digits}}}"; 21 | } 22 | 23 | public bool Equals(IGroup? other) 24 | { 25 | return other?.Hash == Hash; 26 | } 27 | 28 | public int Hash => Mod; 29 | 30 | public ZnInt Neutral() 31 | { 32 | return new(Mod, 0); 33 | } 34 | 35 | public ZnInt Invert(ZnInt e) 36 | { 37 | if (Mod != e.Mod) 38 | throw new GroupException(GroupExceptionType.BaseGroup); 39 | 40 | return e.Opp(); 41 | } 42 | 43 | public ZnInt Op(ZnInt e1, ZnInt e2) 44 | { 45 | if (Mod != e1.Mod || Mod != e2.Mod) 46 | throw new GroupException(GroupExceptionType.BaseGroup); 47 | 48 | return e1.Add(e2); 49 | } 50 | 51 | public ZnInt this[params ValueType[] us] 52 | { 53 | get 54 | { 55 | try 56 | { 57 | var u = Convert.ToInt32(us[0]); 58 | return new ZnInt(Mod, u); 59 | } 60 | catch 61 | { 62 | throw new GroupException(GroupExceptionType.GroupDef); 63 | } 64 | } 65 | } 66 | 67 | public IEnumerable GetGenerators() 68 | { 69 | yield return new ZnInt(Mod, 1); 70 | } 71 | 72 | public IEnumerable GetElements() 73 | { 74 | yield return Neutral(); 75 | } 76 | 77 | public IEnumerator GetEnumerator() 78 | { 79 | return GetElements().GetEnumerator(); 80 | } 81 | 82 | IEnumerator IEnumerable.GetEnumerator() 83 | { 84 | return GetElements().GetEnumerator(); 85 | } 86 | 87 | public override int GetHashCode() 88 | { 89 | return Hash; 90 | } 91 | 92 | public override string ToString() 93 | { 94 | return Name; 95 | } 96 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/LWE/NTTInfos.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.VecSpace; 2 | using FastGoat.UserGroup.Integers; 3 | 4 | namespace FastGoat.UserGroup.LWE; 5 | 6 | public record NTTInfos( 7 | int n, 8 | ZnBigInt w, 9 | KMatrix ntt, 10 | ZnBigInt[] wPows, 11 | Rational t, 12 | KMatrix intt, 13 | ZnBigInt[] iwPows); -------------------------------------------------------------------------------- /FastGoat/UserGroup/LWE/RegevCipher.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures.VecSpace; 2 | using FastGoat.UserGroup.Integers; 3 | 4 | namespace FastGoat.UserGroup.LWE; 5 | 6 | public readonly struct RegevCipher 7 | { 8 | public Vec A { get; } 9 | public ZnBigInt B { get; } 10 | 11 | public RegevCipher(Vec a, ZnBigInt b) 12 | { 13 | (A, B) = (a, b); 14 | } 15 | 16 | public override string ToString() => $"[{A}, {B}]"; 17 | 18 | public static implicit operator RegevCipher((Vec a, ZnBigInt b) e) => new(e.a, e.b); 19 | public static RegevCipher operator +(RegevCipher a, RegevCipher b) => new(a.A + b.A, a.B + b.B); 20 | public static RegevCipher operator +(RegevCipher a, int b) => new(a.A, a.B + b); 21 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Matrix/Mat.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Integers; 5 | 6 | namespace FastGoat.UserGroup.Matrix; 7 | 8 | public struct Mat : IElt 9 | { 10 | public int[] Table { get; } 11 | public GL GL { get; } 12 | 13 | public Mat(GL gl) 14 | { 15 | GL = gl; 16 | Table = GL.TableNeutral.ToArray(); 17 | Hash = GL.HashNeutral; 18 | } 19 | 20 | public Mat(GL gl, int hash, int[] table) 21 | { 22 | GL = gl; 23 | Table = table.ToArray(); 24 | Hash = hash; 25 | } 26 | 27 | public bool IsUT 28 | { 29 | get 30 | { 31 | var n = GL.N; 32 | var rg = n.Range(); 33 | var t0 = Table; 34 | return rg.Grid2D(rg).Where(e => e.t1 > e.t2).All(e => t0[e.t1 * n + e.t2] == 0); 35 | } 36 | } 37 | 38 | public bool IsLT 39 | { 40 | get 41 | { 42 | var n = GL.N; 43 | var rg = n.Range(); 44 | var t0 = Table; 45 | return rg.Grid2D(rg).Where(e => e.t1 < e.t2).All(e => t0[e.t1 * n + e.t2] == 0); 46 | } 47 | } 48 | 49 | public bool IsDiag 50 | { 51 | get 52 | { 53 | var n = GL.N; 54 | var rg = n.Range(); 55 | var t0 = Table; 56 | return rg.Grid2D(rg).Where(e => e.t1 != e.t2).All(e => t0[e.t1 * n + e.t2] == 0); 57 | } 58 | } 59 | 60 | public bool Is2ndDiag 61 | { 62 | get 63 | { 64 | var n = GL.N; 65 | var rg = n.Range(); 66 | var t0 = Table; 67 | return rg.Grid2D(rg).Where(e => e.t1 + e.t2 != n - 1).All(e => t0[e.t1 * n + e.t2] == 0); 68 | } 69 | } 70 | 71 | public bool IsSym 72 | { 73 | get 74 | { 75 | var n = GL.N; 76 | var rg = n.Range(); 77 | var t0 = Table; 78 | return rg.Grid2D(rg).Where(e => e.t1 < e.t2).All(e => t0[e.t1 * n + e.t2] == t0[e.t2 * n + e.t1]); 79 | } 80 | } 81 | 82 | public int Det => GL.Det(this); 83 | public int Trace 84 | { 85 | get 86 | { 87 | var n = GL.N; 88 | var t0 = Table; 89 | return n.SeqLazy().Sum(k => t0[k * (n + 1)]) % GL.P; 90 | } 91 | } 92 | 93 | public Mat T 94 | { 95 | get 96 | { 97 | var n = GL.N; 98 | var rg = n.Range(); 99 | var t0 = Table; 100 | return GL.Create(rg.Grid2D(rg).Select(e => t0[e.t2 * n + e.t1]).ToArray()); 101 | } 102 | } 103 | 104 | public bool IsOrder(int ord) 105 | { 106 | if (IntExt.PowMod(Det, ord, GL.P) != 1) 107 | return false; 108 | 109 | return Group.ElementIsOrder(GL, this, ord); 110 | } 111 | 112 | public Mat At(Tuple2Array at, int value) => GL.At(Table, at, value); 113 | public bool Equals(Mat other) => Hash == other.Hash && Table.SequenceEqual(other.Table); 114 | 115 | public int CompareTo(Mat other) => Table.SequenceCompareTo(other.Table); 116 | 117 | public int Hash { get; } 118 | public IGroup BaseGroup => GL; 119 | 120 | public override int GetHashCode() => Hash; 121 | 122 | public override string ToString() 123 | { 124 | var mod = GL.P; 125 | return Table.Select(i => new ZnInt(mod, i)).ToKMatrix(GL.N).ToString(); 126 | } 127 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Matrix/MatFq.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | using FastGoat.Structures.VecSpace; 4 | using FastGoat.UserGroup.Integers; 5 | 6 | namespace FastGoat.UserGroup.Matrix; 7 | 8 | public struct MatFq : IElt 9 | { 10 | public EPoly[] Table { get; } 11 | public GLnq GLnq { get; } 12 | 13 | public MatFq(GLnq gl, EPoly[] table) 14 | { 15 | GLnq = gl; 16 | var n = gl.Fq.F.Degree; 17 | var hash = table.SelectMany(a => a.Poly.CoefsExtended(n)) 18 | .Aggregate(gl.Hash, (acc, h) => (acc, h.Hash).GetHashCode()); 19 | Table = table.ToArray(); 20 | Hash = hash; 21 | } 22 | 23 | public EPoly Det => GLnq.Determinant(this); 24 | 25 | public bool IsOrder(int ord) 26 | { 27 | return Group.ElementIsOrder(GLnq, this, ord); 28 | } 29 | 30 | public MatFq T 31 | { 32 | get 33 | { 34 | var table = Table.ToArray(); 35 | var n = GLnq.N; 36 | for (int i = 0; i < n; i++) 37 | for (int j = 0; j < n; j++) 38 | table[j * n + i] = Table[i * n + j]; 39 | 40 | return new(GLnq, table); 41 | } 42 | } 43 | 44 | public bool IsUT 45 | { 46 | get 47 | { 48 | var n = GLnq.N; 49 | var rg = n.Range(); 50 | var t0 = Table; 51 | return rg.Grid2D(rg).Where(e => e.t1 > e.t2).All(e => t0[e.t1 * n + e.t2].IsZero()); 52 | } 53 | } 54 | 55 | public bool IsLT 56 | { 57 | get 58 | { 59 | var n = GLnq.N; 60 | var rg = n.Range(); 61 | var t0 = Table; 62 | return rg.Grid2D(rg).Where(e => e.t1 < e.t2).All(e => t0[e.t1 * n + e.t2].IsZero()); 63 | } 64 | } 65 | 66 | public bool IsDiag 67 | { 68 | get 69 | { 70 | var n = GLnq.N; 71 | var rg = n.Range(); 72 | var t0 = Table; 73 | return rg.Grid2D(rg).Where(e => e.t1 != e.t2).All(e => t0[e.t1 * n + e.t2].IsZero()); 74 | } 75 | } 76 | 77 | public bool Is2ndDiag 78 | { 79 | get 80 | { 81 | var n = GLnq.N; 82 | var rg = n.Range(); 83 | var t0 = Table; 84 | return rg.Grid2D(rg).Where(e => e.t1 + e.t2 != n - 1).All(e => t0[e.t1 * n + e.t2].IsZero()); 85 | } 86 | } 87 | 88 | public bool IsSym 89 | { 90 | get 91 | { 92 | var n = GLnq.N; 93 | var rg = n.Range(); 94 | var t0 = Table; 95 | return rg.Grid2D(rg).Where(e => e.t1 < e.t2).All(e => t0[e.t1 * n + e.t2].Equals(t0[e.t2 * n + e.t1])); 96 | } 97 | } 98 | 99 | public bool Equals(MatFq other) => Table.SequenceEqual(other.Table); 100 | 101 | public int CompareTo(MatFq other) => Table.SequenceCompareTo(other.Table); 102 | 103 | public int Hash { get; } 104 | public override int GetHashCode() => Hash; 105 | 106 | public override string ToString() 107 | { 108 | return Table.ToKMatrix(GLnq.N).ToString(); 109 | } 110 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Padic/Modulus.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace FastGoat.UserGroup.Padic; 4 | 5 | public readonly struct Modulus : IEquatable 6 | { 7 | public int P { get; } 8 | public int O { get; } 9 | public BigInteger Mod { get; } 10 | 11 | public Modulus() 12 | { 13 | P = 2; 14 | O = 1; 15 | Mod = 2; 16 | } 17 | 18 | public Modulus(int p, int o) 19 | { 20 | if (p < 2 || o < 1) 21 | throw new ArgumentException($"p={p} must be greater than 2 and o={o} must be greater than 1."); 22 | 23 | P = p; 24 | O = o; 25 | Mod = BigInteger.Pow(P, O); 26 | } 27 | 28 | public bool Equals(Modulus other) => P == other.P && O == other.O; 29 | 30 | public static Modulus operator ++(Modulus i) => new(i.P, i.O + 1); 31 | public static Modulus operator *(Modulus i, int k) => k > 0 ? new(i.P, i.O * k) : throw new(); 32 | public ZnBInt Zero => new(this, 0); 33 | public override int GetHashCode() => (P, O).GetHashCode(); 34 | 35 | public override string ToString() => $"{P}^{O} = {Mod}"; 36 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Padic/Valuation.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using FastGoat.Commons; 3 | 4 | namespace FastGoat.UserGroup.Padic; 5 | 6 | public readonly struct Valuation : IEquatable, IComparable, 7 | IComparisonOperators 8 | { 9 | private readonly int v; 10 | private readonly bool isInfinity; 11 | public static Valuation Infinity => new(); 12 | 13 | public Valuation() 14 | { 15 | isInfinity = true; 16 | v = 0; 17 | } 18 | 19 | public Valuation(int v) 20 | { 21 | isInfinity = false; 22 | this.v = v; 23 | } 24 | 25 | public bool IsInfinity => isInfinity; 26 | public int V => !isInfinity ? v : throw new ArgumentException("Infinite valuation"); 27 | 28 | public static Valuation operator +(Valuation a, Valuation b) => 29 | a.IsInfinity || b.IsInfinity ? new() : new(a.v + b.v); 30 | 31 | public static Valuation operator -(Valuation a, Valuation b) => 32 | a.IsInfinity || b.IsInfinity ? new() : new(a.v - b.v); 33 | 34 | public bool Equals(Valuation other) => 35 | (IsInfinity && other.IsInfinity) || (!IsInfinity && !other.IsInfinity && v == other.v); 36 | 37 | public override bool Equals(object? obj) 38 | { 39 | return obj is Valuation other && Equals(other); 40 | } 41 | 42 | public int CompareTo(Valuation other) 43 | { 44 | if (Equals(other)) 45 | return 0; 46 | 47 | if (IsInfinity) 48 | return 1; 49 | 50 | if (other.IsInfinity) 51 | return -1; 52 | 53 | return v.CompareTo(other.v); 54 | } 55 | 56 | public override int GetHashCode() => (IsInfinity, v).GetHashCode(); 57 | public override string ToString() => IsInfinity ? "∞" : $"{v}"; 58 | 59 | public static (Valuation, BigInteger) Of(int p, BigInteger n) 60 | { 61 | if (n.IsZero) 62 | return (new(), n); 63 | 64 | var (v, n0) = PadicExt.GetValuation(p, n); 65 | return (new(v), n0); 66 | } 67 | 68 | public static bool operator ==(Valuation left, Valuation right) => left.Equals(right); 69 | 70 | public static bool operator !=(Valuation left, Valuation right) => !left.Equals(right); 71 | 72 | public static bool operator >(Valuation left, Valuation right) => left.CompareTo(right) == 1; 73 | 74 | public static bool operator >=(Valuation left, Valuation right) => left.CompareTo(right) >= 0; 75 | 76 | public static bool operator <(Valuation left, Valuation right) => left.CompareTo(right) == -1; 77 | 78 | public static bool operator <=(Valuation left, Valuation right) => left.CompareTo(right) <= 0; 79 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Perms/Perm.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.UserGroup.Perms; 5 | 6 | public enum DisplayPerm 7 | { 8 | Table, 9 | Cycles, 10 | TableComma, 11 | CyclesComma 12 | } 13 | 14 | public struct Perm : IElt 15 | { 16 | public static DisplayPerm Style { get; set; } = DisplayPerm.Cycles; 17 | public int Hash { get; } 18 | public int[] Table { get; } 19 | public IGroup BaseGroup { get; } 20 | public Sn Sn { get; } 21 | 22 | public Perm() 23 | { 24 | BaseGroup = Sn = new Sn(2); 25 | Table = new[] { 0, 1 }; 26 | Hash = IntExt.GenHash(2, Table); 27 | } 28 | 29 | public Perm(Sn sn) 30 | { 31 | BaseGroup = Sn = sn; 32 | Table = sn.N.Range(); 33 | Hash = IntExt.GenHash(sn.N, Table); 34 | } 35 | 36 | public Perm(Sn sn, int[] arr, int hash) 37 | { 38 | BaseGroup = Sn = sn; 39 | Table = arr.ToArray(); 40 | Hash = hash; 41 | } 42 | 43 | public int CompareTo(Perm other) 44 | { 45 | if (!BaseGroup.Equals(other.BaseGroup)) 46 | throw new GroupException(GroupExceptionType.BaseGroup); 47 | 48 | return Table.SequenceCompareTo(other.Table); 49 | } 50 | 51 | public bool Equals(Perm other) 52 | { 53 | return Sn.N < 11 54 | ? Hash == other.Hash 55 | : Hash == other.Hash && Table.SequenceEqual(other.Table); 56 | } 57 | 58 | public override int GetHashCode() 59 | { 60 | return Hash; 61 | } 62 | 63 | public int[][] Orbits => IntExt.PermutationToCycles(Sn.N, Table); 64 | public int[] PermType => Orbits.Select(l => l.Length).Order().ToArray(); 65 | public int Sgn => (-1).Pow(Orbits.Length); 66 | public string PermTypeStr => $"({PermType.Glue(" ")})"; 67 | public string SgnStr => Sgn == 1 ? "(+)" : "(-)"; 68 | 69 | public T[] Apply(T[] ts) 70 | { 71 | if (ts.Length != Sn.N) 72 | throw new GroupException(GroupExceptionType.GroupDef); 73 | 74 | return Table.Select(i => ts[i]).ToArray(); 75 | } 76 | 77 | public override string ToString() 78 | { 79 | if (Style == DisplayPerm.Table) 80 | return $"[{Table.Select(a => a + 1).Glue(" ")}]"; 81 | if (Style == DisplayPerm.TableComma) 82 | return $"[{Table.Select(a => a + 1).Glue(", ")}]"; 83 | 84 | var cycles = Orbits.Where(a => a.Length > 1).ToArray(); 85 | if (Style == DisplayPerm.Cycles) 86 | { 87 | var strCycles = cycles.Select(a => $"({a.Select(b => b + 1).Glue(" ")})").Glue(); 88 | return $"[{strCycles}]"; 89 | } 90 | else 91 | { 92 | var strCycles = cycles.Select(a => $"({a.Select(b => b + 1).Glue(", ")})").Glue(", "); 93 | return $"[{strCycles}]"; 94 | } 95 | } 96 | 97 | public override bool Equals(object? obj) 98 | { 99 | return obj is Perm perm && Equals(perm); 100 | } 101 | 102 | public static Perm operator *(Perm a, Perm b) => a.BaseGroup.Op(a, b); 103 | public static Perm operator ^(Perm a, int p) => a.BaseGroup.Times(a, p); 104 | public static bool operator ==(Perm a, Perm b) => a.Equals(b); 105 | public static bool operator !=(Perm a, Perm b) => !a.Equals(b); 106 | 107 | public static int CompareOrbits(Perm a, Perm b) 108 | { 109 | if (!a.Sn.Equals(b.Sn)) 110 | throw new(); 111 | 112 | var ca = a.Orbits.Where(e => e.Length > 1).ToArray(); 113 | var cb = b.Orbits.Where(e => e.Length > 1).ToArray(); 114 | ; 115 | 116 | var compNb = ca.Length.CompareTo(cb.Length); 117 | if (compNb != 0) 118 | return compNb; 119 | 120 | ca = ca.OrderBy(e => e, Comparer.Create((e, f) => e.SequenceCompareTo(f))).ThenBy(e => e.Length).ToArray(); 121 | cb = cb.OrderBy(e => e, Comparer.Create((e, f) => e.SequenceCompareTo(f))).ThenBy(e => e.Length).ToArray(); 122 | foreach (var (e, f) in ca.Zip(cb)) 123 | { 124 | var compL = e.Length.CompareTo(f.Length); 125 | if (compL != 0) 126 | return compL; 127 | 128 | var compEF = e.SequenceCompareTo(f); 129 | if (compEF != 0) 130 | return compEF; 131 | } 132 | 133 | return 0; 134 | } 135 | 136 | public static Comparer OrbitsComparer => Comparer.Create(CompareOrbits); 137 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Perms/Sn.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | 5 | namespace FastGoat.UserGroup.Perms; 6 | 7 | public struct Sn : IGroup 8 | { 9 | public int Hash { get; } 10 | public string Name { get; } 11 | public int N { get; } 12 | readonly int[] _cache; 13 | 14 | public Sn() 15 | { 16 | N = Hash = 2; 17 | _cache = new int[2]; 18 | Name = $"S{N}"; 19 | } 20 | 21 | public Sn(int n) 22 | { 23 | if (n < 1) 24 | throw new GroupException(GroupExceptionType.GroupDef); 25 | 26 | N = Hash = n; 27 | _cache = new int[n]; 28 | Name = $"S{N}"; 29 | } 30 | 31 | public IEnumerable GetGenerators() 32 | { 33 | if (N > 1) 34 | { 35 | yield return this[(1, 2)]; 36 | yield return ComposesCycles(new Tuple2Array(Enumerable.Range(1, N).ToArray())); 37 | } 38 | else 39 | yield return this[1]; 40 | } 41 | 42 | public IEnumerable GetElements() 43 | { 44 | return IntExt.GetPermutations(N).Select(CreateElement); 45 | } 46 | 47 | public Perm Neutral() => new Perm(this); 48 | 49 | public Perm Invert(Perm e) 50 | { 51 | if (!Equals(e.BaseGroup)) 52 | throw new GroupException(GroupExceptionType.BaseGroup); 53 | 54 | var hash = IntExt.InvertPermutation(e.Table, _cache); 55 | return new Perm(this, _cache, hash); 56 | } 57 | 58 | public Perm Op(Perm e1, Perm e2) 59 | { 60 | if (!Equals(e1.BaseGroup) || !Equals(e2.BaseGroup)) 61 | throw new GroupException(GroupExceptionType.BaseGroup); 62 | 63 | var hash = IntExt.ComposePermutation(e1.Table, e2.Table, _cache); 64 | return new Perm(this, _cache, hash); 65 | } 66 | 67 | public Perm CreateElement(params int[] table) 68 | { 69 | var t0 = table.Select(i => i - 1).ToArray(); 70 | if (!IntExt.CheckTable(N, t0)) 71 | throw new GroupException(GroupExceptionType.GroupDef); 72 | 73 | var hash = IntExt.GenHash(N, t0); 74 | var p = new Perm(this, t0, hash); 75 | return p; 76 | } 77 | 78 | public Perm CreateElementTable(params int[] table) 79 | { 80 | if (!IntExt.CheckTable(N, table)) 81 | throw new GroupException(GroupExceptionType.GroupDef); 82 | 83 | var hash = IntExt.GenHash(N, table); 84 | var p = new Perm(this, table, hash); 85 | return p; 86 | } 87 | 88 | public Perm Cycle(params int[] cycle) => ComposesCycles(new Tuple2Array(cycle)); 89 | 90 | public Perm ComposesCycles(params Tuple2Array[] cycles) 91 | { 92 | Neutral().Table.CopyTo(_cache, 0); 93 | foreach (var e in cycles) 94 | { 95 | var cycle = e.Table.Select(i => i - 1).ToArray(); 96 | if (!IntExt.CheckCycle(N, cycle)) 97 | throw new GroupException(GroupExceptionType.GroupDef); 98 | 99 | IntExt.ApplyCycle(_cache, cycle); 100 | } 101 | 102 | var hash = IntExt.GenHash(N, _cache); 103 | return new Perm(this, _cache, hash); 104 | } 105 | 106 | public bool Equals(IGroup? other) => other?.Hash == Hash; 107 | 108 | public Perm this[params ValueType[] us] 109 | { 110 | get 111 | { 112 | var cycles = us.Select(u => (Tuple2Array)u).ToArray(); 113 | if (cycles.Any(c => c.Table.Length == 0)) 114 | throw new GroupException(GroupExceptionType.GroupDef); 115 | 116 | if (cycles.All(c => c.Table.Length == 1) && cycles.Length == N) 117 | { 118 | var table = cycles.SelectMany(c => c.Table).ToArray(); 119 | return CreateElement(table); 120 | } 121 | 122 | if (cycles.Any(c => c.Table.Length == 1)) 123 | throw new GroupException(GroupExceptionType.GroupDef); 124 | 125 | return ComposesCycles(cycles); 126 | } 127 | } 128 | 129 | public IEnumerator GetEnumerator() => GetElements().GetEnumerator(); 130 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 131 | public override string ToString() => Name; 132 | } 133 | -------------------------------------------------------------------------------- /FastGoat/UserGroup/Polynoms/Fq.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.Structures.VecSpace; 5 | using FastGoat.UserGroup.Integers; 6 | 7 | namespace FastGoat.UserGroup.Polynoms; 8 | 9 | public struct Fq : IGroup> 10 | { 11 | public int Q { get; } 12 | public int P { get; } 13 | public int M { get; } 14 | public KPoly F { get; } 15 | public EPoly X { get; } 16 | 17 | public Fq(int q, char x = 'x') 18 | { 19 | Q = q; 20 | ((int p, int m), int[] coefs) = PolynomExt.GetConwayPoly(Q); 21 | P = p; 22 | M = m; 23 | F = new(x, ZnInt.ZnZero(p), coefs.Select(i => new ZnInt(p, i)).ToArray()); 24 | Hash = (Q, "fq").GetHashCode(); 25 | Name = $"F{Q}"; 26 | FullName = Q == P ? Name : $"{Name} = F{P}({x}) = F{P}[{x}]/({F})"; 27 | var gen = p != q ? F.X.Div(F).rem : F.One * (IntExt.Solve_k_pow_m_equal_one_mod_n_strict(p, p - 1)); 28 | X = new(F, gen); 29 | } 30 | 31 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 32 | 33 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 34 | 35 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 36 | 37 | public int Hash { get; } 38 | public string Name { get; } 39 | public string FullName { get; } 40 | public EPoly Zero => X.Zero; 41 | public EPoly One => X.One; 42 | 43 | public EPoly this[params ValueType[] us] 44 | { 45 | get 46 | { 47 | if (us[0] is char x && F.x.Equals(x)) 48 | return X; 49 | if (us[0] is ValueTuple e && F.x.Equals(e.Item1)) 50 | return X.Pow(e.Item2); 51 | if (us[0] is int k) 52 | return X.One.Mul(k); 53 | 54 | throw new GroupException(GroupExceptionType.GroupDef); 55 | } 56 | } 57 | 58 | public IEnumerable> GetElements() 59 | { 60 | yield return Neutral(); 61 | } 62 | 63 | public IEnumerable> GetGenerators() 64 | { 65 | yield return X; 66 | } 67 | 68 | public EPoly Neutral() => X.One; 69 | 70 | public EPoly Invert(EPoly e) => e.Inv(); 71 | 72 | public EPoly Op(EPoly e1, EPoly e2) => e1 * e2; 73 | 74 | public override int GetHashCode() => Hash; 75 | public override string ToString() => Name; 76 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Polynoms/GFp.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Numerics; 3 | using FastGoat.Commons; 4 | using FastGoat.Examples; 5 | using FastGoat.Structures; 6 | using FastGoat.Structures.CartesianProduct; 7 | using FastGoat.Structures.GenericGroup; 8 | using FastGoat.Structures.VecSpace; 9 | using FastGoat.UserGroup.EllCurve; 10 | using FastGoat.UserGroup.Integers; 11 | using FastGoat.UserGroup.Padic; 12 | 13 | namespace FastGoat.UserGroup.Polynoms; 14 | 15 | public class GFp : IGroup> 16 | { 17 | public GFp(string name, EPoly e) 18 | { 19 | if (!IntExt.Primes10000.Contains(e.P)) 20 | throw new GroupException(GroupExceptionType.GroupDef); 21 | 22 | P = e.P; 23 | Name = name; 24 | 25 | F = e.F; 26 | X = e.X; 27 | M = F.Degree; 28 | 29 | Hash = e.Hash; 30 | } 31 | 32 | public GFp(string name, KPoly f) : this(name, FG.EPoly(f)) 33 | { 34 | } 35 | 36 | public GFp(KPoly f) : this($"F{f.P}[{f.x}]/({f})", FG.EPoly(f)) 37 | { 38 | } 39 | 40 | public GFp(EPoly e) : this($"F{e.P}[{e.F.x}]/({e.F})", e) 41 | { 42 | } 43 | 44 | public KPoly F { get; } 45 | public EPoly X { get; } 46 | public int M { get; } 47 | public int P { get; } 48 | 49 | public IEnumerator> GetEnumerator() => GetElements().GetEnumerator(); 50 | 51 | IEnumerator IEnumerable.GetEnumerator() 52 | { 53 | return GetEnumerator(); 54 | } 55 | 56 | public bool Equals(IGroup>? other) => other?.Hash == Hash; 57 | 58 | public int Hash { get; } 59 | public string Name { get; } 60 | 61 | public EPoly this[params ValueType[] us] 62 | { 63 | get 64 | { 65 | if (us[0] is char x && F.x.Equals(x)) 66 | return X; 67 | if (us[0] is EPoly e && e.P == P && e.Poly.Equals(F) && !e.IsZero()) 68 | return e; 69 | if (us[0] is int k && k != 0) 70 | return X * k; 71 | 72 | throw new GroupException(GroupExceptionType.GroupDef); 73 | } 74 | } 75 | 76 | public IEnumerable> GetElements() 77 | { 78 | yield return Neutral(); 79 | } 80 | 81 | public IEnumerable> GetGenerators() 82 | { 83 | yield return NumberTheory.PrimitiveRoot(X); 84 | } 85 | 86 | public EPoly Neutral() => X.One; 87 | 88 | public EPoly Invert(EPoly e) => e.Inv(); 89 | 90 | public EPoly Op(EPoly e1, EPoly e2) => e1 * e2; 91 | 92 | public override int GetHashCode() => Hash; 93 | public override string ToString() => Name; 94 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/StringExt.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | 5 | namespace FastGoat.UserGroup.Words; 6 | 7 | public static class StringExt 8 | { 9 | static Regex regX = new Regex(@"([a-zA-Z])((\-{1}\d{1,})|(\d{0,}))"); 10 | 11 | static (char c, int pow) ToLowerForm(char c, int p) 12 | { 13 | var c0 = char.IsLower(c) ? c : char.ToLower(c); 14 | var p0 = c == c0 ? p : -p; 15 | return (c0, p0); 16 | } 17 | 18 | static char Revert(char c) => char.IsLower(c) ? char.ToUpper(c) : char.ToLower(c); 19 | public static IEnumerable Revert(this IEnumerable letters) => letters.Reverse().Select(Revert); 20 | 21 | public static IEnumerable Add(this IEnumerable w0, IEnumerable w1) 22 | { 23 | var s = new Stack(w0); 24 | foreach (var c in w1) 25 | { 26 | if (s.Count == 0) 27 | { 28 | s.Push(c); 29 | } 30 | else 31 | { 32 | var c0 = s.Peek(); 33 | if ((char.IsLower(c) && char.IsUpper(c0) && c0 == char.ToUpper(c)) || 34 | (char.IsUpper(c) && char.IsLower(c0) && c0 == char.ToLower(c))) 35 | { 36 | s.Pop(); 37 | } 38 | else 39 | { 40 | s.Push(c); 41 | } 42 | } 43 | } 44 | 45 | return s.Reverse(); 46 | } 47 | 48 | static IEnumerable<(char c, int pow)> Reduce(IEnumerable<(char c, int pow)> letters) 49 | { 50 | Stack<(char c, int pow)> stack = new(); 51 | foreach (var l in letters) 52 | { 53 | if (stack.Count == 0) 54 | { 55 | stack.Push(l); 56 | continue; 57 | } 58 | else if (l.c == stack.Peek().c) 59 | { 60 | var l0 = stack.Pop(); 61 | var p = l.pow + l0.pow; 62 | if (p != 0) 63 | stack.Push((l.c, p)); 64 | } 65 | else 66 | stack.Push(l); 67 | } 68 | 69 | return stack.Reverse(); 70 | } 71 | 72 | static IEnumerable<(char c, int pow)> ParseReducedWord(string word) 73 | { 74 | List<(char c, int pow)> letters = new(); 75 | foreach (Match m in regX.Matches(word)) 76 | { 77 | var powStr = m.Groups[2].Value; 78 | var c = char.Parse(m.Groups[1].Value); 79 | var p = string.IsNullOrEmpty(powStr) ? 1 : int.Parse(powStr); 80 | letters.Add(ToLowerForm(c, p)); 81 | } 82 | 83 | return Reduce(letters); 84 | } 85 | 86 | static string ExtendLetters((char c, int pow) e) 87 | { 88 | var c0 = e.pow < 0 ? char.ToUpper(e.c) : e.c; 89 | var p0 = e.pow < 0 ? -e.pow : e.pow; 90 | return String.Join("", Enumerable.Repeat(c0, p0)); 91 | } 92 | 93 | static string OneLetter((char c, int pow) e) 94 | { 95 | return e.pow == 1 ? $"{e.c}" : $"{e.c}{e.pow}"; 96 | } 97 | 98 | static string ExtendLetters(IEnumerable<(char c, int pow)> letters) => letters.Select(ExtendLetters).Glue(); 99 | public static string ReducedWordForm1(string word) => ParseReducedWord(word).Select(OneLetter).Glue(); 100 | public static string ReducedWordForm2(string word) => ExtendLetters(ParseReducedWord(word)); 101 | 102 | public static string ExpandRelator(string r) 103 | { 104 | var nbEq = r.Count(c => c == '='); 105 | if (nbEq == 0) 106 | { 107 | return ReducedWordForm2(r); 108 | } 109 | else if (nbEq == 1) 110 | { 111 | var sp = r.Split('='); 112 | var r1 = ReducedWordForm2(sp[0]); 113 | var r2 = ReducedWordForm2(sp[1]); 114 | var rf = r1.Add(r2.Revert()); 115 | return rf.Glue(); 116 | } 117 | 118 | throw new GroupException(GroupExceptionType.GroupDef); 119 | } 120 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Circuit.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.UserGroup.Words.Tools; 4 | 5 | public readonly partial struct Circuit 6 | { 7 | public Class Class { get; } 8 | public Relator Relator { get; } 9 | public Class?[] Content { get; } 10 | 11 | public Circuit(Class cl, Relator relator) 12 | { 13 | Class = cl; 14 | Relator = relator; 15 | Content = new Class?[relator.Length + 1]; 16 | Content[0] = Content[relator.Length] = cl; 17 | } 18 | 19 | public int NbUnknowns => Content.Count(c => c is null); 20 | public bool IsComplete => NbUnknowns == 0; 21 | 22 | public (Class? cl1, Class? cl2) UpdateCircuit() 23 | { 24 | var leftCircuit = UpdateCircuit(true); 25 | if (leftCircuit.cl1 is not null) 26 | return leftCircuit; 27 | 28 | var rightCircuit = UpdateCircuit(false); 29 | if (rightCircuit.cl1 is not null) 30 | return rightCircuit; 31 | 32 | return (null, null); 33 | } 34 | 35 | public void Substitute(Class cl, Class err) 36 | { 37 | for (int i = 0; i < Content.Length; i++) 38 | { 39 | var cl0 = Content[i]; 40 | if (cl0 is null) 41 | continue; 42 | 43 | if (cl0.V == err.V) 44 | Content[i] = cl; 45 | } 46 | } 47 | 48 | private (Class? cl1, Class? cl2) UpdateCircuit(bool leftDir) 49 | { 50 | var length = Relator.Length; 51 | var seq = leftDir ? length.Range() : length.Range(start: length, step: -1); 52 | var range = seq.Select(k => leftDir ? (k, k + 1, k) : (k, k - 1, k - 1)).ToArray(); 53 | foreach (var (k0, k1, i) in range) 54 | { 55 | var cl0 = Content[k0]!; 56 | var g0 = leftDir ? Relator.Gens[i] : Relator.Gens[i].Invert(); 57 | var cl1 = Content[k1]; 58 | if (cl1 is null) 59 | { 60 | if (cl0.HasEdge(g0)) 61 | Content[k1] = cl0[g0]; 62 | else 63 | break; 64 | } 65 | else 66 | { 67 | if (cl0.HasEdge(g0)) 68 | { 69 | var cl2 = cl0[g0]; 70 | if (cl1.V != cl2.V) 71 | return (cl1, cl2); 72 | } 73 | else 74 | cl0[g0] = cl1; 75 | } 76 | } 77 | 78 | return (null, null); 79 | } 80 | 81 | public (Class? cl, Gen g) FindCandidate() 82 | { 83 | var (_, li) = Content.Select((c, k) => (c, k)).FirstOrDefault(e => e.c is null, (null, -1)); 84 | var (_, ri) = Content.Select((c, k) => (c, k)).LastOrDefault(e => e.c is null, (null, -1)); 85 | if (li == -1 && ri == -1) 86 | return (null, new()); 87 | 88 | var lc = Content[li - 1]!; 89 | var rc = Content[ri + 1]!; 90 | var lg = Relator.Gens[li - 1]; 91 | var rg = Relator.Gens[ri].Invert(); 92 | if (lc.V == rc.V) 93 | { 94 | if (lg.CompareTo(rg) < 1) 95 | return (lc, lg); 96 | else 97 | return (rc, rg); 98 | } 99 | else if (lc.V < rc.V) 100 | return (lc, lg); 101 | else 102 | return (rc, rg); 103 | } 104 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Circuit.partial.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.UserGroup.Words.Tools; 2 | 3 | public readonly partial struct Circuit 4 | { 5 | public List<(Class i, Gen s)> NotColoured 6 | { 7 | get 8 | { 9 | var gens = Relator.Gens; 10 | return Content.Select((c, k) => (c!, k)).SkipLast(1) 11 | .Select(e => (i: e.Item1, s: gens[e.k])) 12 | .Where(e => !e.i.Coloured[e.s]) 13 | .ToList(); 14 | } 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Class.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | 3 | namespace FastGoat.UserGroup.Words.Tools; 4 | 5 | public partial class Class 6 | { 7 | public int V { get; set; } 8 | public Graph G { get; } 9 | 10 | public bool IsComplete { get; set; } 11 | public List Circuits { get; } 12 | 13 | public Class(int v, Graph g) 14 | { 15 | V = v; 16 | G = g; 17 | Edges = new(G.NbGens * 2); 18 | Circuits = G.Relators.Select(rel => new Circuit(this, rel)).ToList(); 19 | if (v == 0) 20 | { 21 | IsComplete = true; 22 | Circuits.Clear(); 23 | } 24 | } 25 | private Dictionary Edges { get; } 26 | public bool HasEdge(Gen g) => Edges.ContainsKey(g); 27 | public IEnumerable> GetEdges() => Edges; 28 | 29 | public Class this[Gen index] 30 | { 31 | get => Edges[index]; 32 | set 33 | { 34 | var cl = Edges[index] = value; 35 | cl.Edges.TryAdd(index.Invert(), this); 36 | } 37 | } 38 | 39 | public (Class? cl1, Class? cl2) UpdateClass() 40 | { 41 | if (IsComplete) 42 | return (null, null); 43 | 44 | IsComplete = false; 45 | foreach (var circuit in Circuits) 46 | { 47 | var e = circuit.UpdateCircuit(); 48 | if (e.cl1 is not null) 49 | return e; 50 | } 51 | 52 | IsComplete = Circuits.All(c => c.IsComplete); 53 | return (null, null); 54 | } 55 | 56 | public void Substitute(Class cl, Class err) 57 | { 58 | foreach (var (g, cl0) in Edges.ToArray()) 59 | { 60 | if (cl0.V == err.V) 61 | Edges[g] = cl; 62 | } 63 | 64 | foreach (var circuit in Circuits) 65 | { 66 | circuit.Substitute(cl, err); 67 | } 68 | } 69 | 70 | public (Class? cl, Gen g) FindCandidate() 71 | { 72 | return Circuits.Where(c => !c.IsComplete) 73 | .Select(c => c.FindCandidate()) 74 | .FirstOrDefault(e => e.Item1 is not null, (null, new())); 75 | } 76 | 77 | public string Display(int digits) 78 | { 79 | var fmt = $"{{0,{digits + 1}}}"; 80 | var s0 = Circuits.SelectMany(c => c.Content.SkipLast(1)).Append(this).Glue("", fmt); 81 | var s1 = (s0 + " ").ToArray(); 82 | foreach (var k in G.Separators) 83 | s1[(digits + 1) * k] = s1[(digits + 1) * (k + 1)] = '│'; 84 | 85 | var s2 = s1.Glue(); 86 | return s2; 87 | } 88 | 89 | public override string ToString() => $"{V}"; 90 | 91 | public static Class Min(Class a, Class b) => a.V.CompareTo(b.V) <= 0 ? a : b; 92 | public static Class Max(Class a, Class b) => a.V.CompareTo(b.V) >= 0 ? a : b; 93 | public static (Class min, Class max) MinMax(Class a, Class b) => (Min(a, b), Max(a, b)); 94 | 95 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Class.partial.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.UserGroup.Words.Tools; 2 | 3 | public partial class Class 4 | { 5 | public static Class? Null => null; 6 | public Gen STGen { get; set; } 7 | public Class? STClass { get; set; } 8 | public List Word { get; } = new(); 9 | public List WordInv { get; } = new(); 10 | public Dictionary Coloured { get; set; } = new(); 11 | 12 | public void Color(Gen g) 13 | { 14 | Coloured[g] = Edges[g].Coloured[g.Invert()] = true; 15 | } 16 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Gen.cs: -------------------------------------------------------------------------------- 1 | namespace FastGoat.UserGroup.Words.Tools; 2 | 3 | public readonly struct Gen : IEquatable, IComparable 4 | { 5 | public const char Id = 'i'; 6 | public char V { get; } 7 | 8 | public Gen(char v0 = Id) 9 | { 10 | V = v0; 11 | } 12 | public bool Equals(Gen other) => other.V == V; 13 | 14 | private char ToLower() => V == Id ? '0' : char.ToLower(V); 15 | public int CompareTo(Gen other) 16 | { 17 | var comp = ToLower().CompareTo(other.ToLower()); 18 | if (comp != 0) 19 | return comp; 20 | 21 | return -V.CompareTo(other.V); 22 | } 23 | 24 | public override int GetHashCode() => V; 25 | 26 | public Gen Invert() => V == Id ? this : new(char.IsLower(V) ? char.ToUpper(V) : char.ToLower(V)); 27 | public override string ToString() => $"{V}"; 28 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Tools/Relator.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.UserGroup.Words.Tools; 5 | 6 | public struct Relator : IElt 7 | { 8 | public Gen[] Gens { get; } 9 | 10 | public Relator(int idx, Gen[] gens) 11 | { 12 | Hash = idx; 13 | Gens = gens; 14 | } 15 | 16 | public int Length => Gens.Length; 17 | 18 | public bool Equals(Relator other) => Hash == other.Hash; 19 | 20 | public int CompareTo(Relator other) => Hash.CompareTo(Hash); 21 | 22 | public int Hash { get; } 23 | public string Format(string fmt) => Gens.Glue("", fmt); 24 | 25 | public override int GetHashCode() => Hash; 26 | public override string ToString() => Gens.Glue(","); 27 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/Word.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Commons; 2 | using FastGoat.Structures; 3 | 4 | namespace FastGoat.UserGroup.Words; 5 | 6 | public struct Word : IElt 7 | { 8 | private string _word; 9 | public WordGroupBase WGroup { get; } 10 | public string Get() => _word; 11 | 12 | public Word(WordGroupBase wg) 13 | { 14 | WGroup = wg; 15 | _word = ""; 16 | Hash = (_word, wg).GetHashCode(); 17 | } 18 | 19 | public Word(WordGroupBase wg, IEnumerable letters) 20 | { 21 | WGroup = wg; 22 | _word = letters.Glue(); 23 | Hash = (_word, wg).GetHashCode(); 24 | } 25 | 26 | public bool Equals(Word other) => Hash == other.Hash; 27 | 28 | public int CompareTo(Word other) 29 | { 30 | var compLength = _word.Length.CompareTo(other._word.Length); 31 | if (compLength != 0) 32 | return compLength; 33 | 34 | return _word.SequenceCompareTo(other._word); 35 | } 36 | 37 | public int Hash { get; } 38 | public override int GetHashCode() => Hash; 39 | 40 | public override string ToString() 41 | { 42 | return _word.Length == 0 ? "()" : StringExt.ReducedWordForm1(_word.Glue()); 43 | } 44 | } -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/WordGroup.cs: -------------------------------------------------------------------------------- 1 | using FastGoat.Structures; 2 | using FastGoat.Structures.GenericGroup; 3 | using FastGoat.UserGroup.Words.Tools; 4 | 5 | namespace FastGoat.UserGroup.Words; 6 | 7 | public class WordGroup : ConcreteGroup 8 | { 9 | public Dictionary InvertTable { get; } 10 | public Dictionary<(Word, Word), Word> OpTable { get; } 11 | private int Ord { get; } 12 | public WordGroup(string name, WordGroupBase wg) : base(name, wg, true) 13 | { 14 | WGbase = wg; 15 | Graph = Graph.Run(WGbase.Relators); 16 | Elements = Graph.Words().Select(s => new Word(wg, s)).ToHashSet(); 17 | Ord = Elements.Count; 18 | if (Ord < Group.GetStorageCapacity()) 19 | { 20 | InvertTable = new(2 * Ord); 21 | OpTable = new(2 * Ord * Ord); 22 | } 23 | else 24 | { 25 | InvertTable = new(); 26 | OpTable = new(); 27 | } 28 | 29 | ElementsOrders = Group.ElementsOrders(this, Elements); 30 | PseudoGenerators = new(wg.GetGenerators().ToList()); 31 | GroupType = (Group.IsCommutative(this, PseudoGenerators) 32 | ? GroupType.AbelianGroup 33 | : GroupType.NonAbelianGroup); 34 | 35 | } 36 | 37 | public WordGroup(WordGroupBase wg) : this(wg.Name, wg) 38 | { 39 | } 40 | 41 | public WordGroup(string relators) : this(new WordGroupBase(relators)) 42 | { 43 | } 44 | 45 | public WordGroup(string name, string relators) : this(name, new WordGroupBase(relators)) 46 | { 47 | } 48 | 49 | public WordGroupBase WGbase { get; } 50 | public string Definition => WGbase.Definition; 51 | private Graph Graph { get; } 52 | public IEnumerable Rewrite(IEnumerable s) => Graph.Rewrite(s); 53 | 54 | public bool CheckHomomorphism(IGroup g, Dictionary map) where T : struct, IElt 55 | { 56 | return Graph.CheckHomomorphism(g, map); 57 | } 58 | 59 | public Word this[string s] 60 | { 61 | get 62 | { 63 | var s0 = WGbase[s]; 64 | return new(WGbase, Rewrite(s0.Get())); 65 | } 66 | } 67 | 68 | public new Word this[params ValueType[] us] 69 | { 70 | get 71 | { 72 | var s0 = WGbase[us]; 73 | return new(WGbase, Rewrite(s0.Get())); 74 | } 75 | } 76 | 77 | public override Word Neutral() => new(WGbase); 78 | 79 | public override Word Invert(Word e) 80 | { 81 | if (Ord >= Group.GetStorageCapacity()) 82 | return new(WGbase, Rewrite(e.Get().Revert())); 83 | else 84 | { 85 | if (InvertTable.TryGetValue(e, out var r)) 86 | return r; 87 | 88 | var e0 = new Word(WGbase, Rewrite(e.Get())); 89 | var ei = InvertTable[e0] = new(WGbase, Rewrite(e.Get().Revert())); 90 | return ei; 91 | } 92 | } 93 | 94 | public override Word Op(Word e1, Word e2) 95 | { 96 | if (Ord >= Group.GetStorageCapacity()) 97 | return new(WGbase, Rewrite(e1.Get().Add(e2.Get()))); 98 | else 99 | { 100 | var e12 = (e1, e2); 101 | if (OpTable.TryGetValue(e12, out var r)) 102 | return r; 103 | 104 | var e120 = (new Word(WGbase, Rewrite(e1.Get())), new Word(WGbase, Rewrite(e2.Get()))); 105 | var e3 = OpTable[e120] = new(WGbase, Rewrite(e1.Get().Add(e2.Get()))); 106 | return e3; 107 | } 108 | 109 | return new(WGbase, Rewrite(e1.Get().Add(e2.Get()))); 110 | } 111 | 112 | public void ShowClassTable() => Graph.DisplayTableOps(); 113 | 114 | public void ShowRelatorsTable() => Graph.DisplayTableRelators(); 115 | 116 | } 117 | -------------------------------------------------------------------------------- /FastGoat/UserGroup/Words/WordGroupBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | 5 | namespace FastGoat.UserGroup.Words; 6 | 7 | public class WordGroupBase : IGroup 8 | { 9 | public WordGroupBase(string relators) 10 | { 11 | Hash = Guid.NewGuid().GetHashCode(); 12 | Relators = relators; 13 | Generators = relators.Where(char.IsLetter).Select(char.ToLower).Distinct().Ascending().ToArray(); 14 | Name = $"WG[{Generators.Glue(",")}]"; 15 | Elements = new() { Neutral() }; 16 | } 17 | 18 | private HashSet Elements { get; } 19 | public string Relators { get; } 20 | 21 | private char[] Generators { get; } 22 | public string Definition => $"< ({Generators.Glue(",")}) | {Relators.Replace(" ", "").Replace(",", ", ").Replace("=", " = ")} >"; 23 | 24 | public IEnumerator GetEnumerator() => GetElements().GetEnumerator(); 25 | 26 | IEnumerator IEnumerable.GetEnumerator() => GetElements().GetEnumerator(); 27 | 28 | public bool Equals(IGroup? other) => other?.Hash == Hash; 29 | 30 | public int Hash { get; } 31 | public string Name { get; } 32 | 33 | public Word this[string s] 34 | { 35 | get 36 | { 37 | var s0 = StringExt.ReducedWordForm2(s); 38 | return this[s0.Cast().ToArray()]; 39 | } 40 | } 41 | 42 | public Word this[params ValueType[] us] 43 | { 44 | get 45 | { 46 | if (!us.All(c => c is char c1 && Generators.Contains(char.ToLower(c1)))) 47 | throw new GroupException(GroupExceptionType.GroupDef); 48 | 49 | var s0 = StringExt.ReducedWordForm2(us.Glue()); 50 | return new(this, s0); 51 | } 52 | } 53 | 54 | public IEnumerable GetElements() => Elements; 55 | 56 | public IEnumerable GetGenerators() => Generators.Select(c => new Word(this, new[] { c })).ToArray(); 57 | 58 | public Word Neutral() => new(this); 59 | 60 | public Word Invert(Word e) => new(this, e.Get().Revert()); 61 | 62 | public Word Op(Word e1, Word e2) => new(this, e1.Get().Add(e2.Get())); 63 | 64 | public override int GetHashCode() => Hash; 65 | public override string ToString() => Name; 66 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT-0 No Attribution 2 | 3 | Copyright (c) 2022 aidevnn 4 | 5 | Permission is hereby granted, free of charge, 6 | to any person obtaining a copy of this software 7 | and associated documentation files (the 8 | "Software"), to deal in the Software without 9 | restriction, including without limitation the 10 | rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of 12 | the Software, and to permit persons to whom the 13 | Software is furnished to do so. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT 16 | WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 17 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 21 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /Tests/GLnpUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using FastGoat.Commons; 4 | using FastGoat.Structures; 5 | using FastGoat.UserGroup.Matrix; 6 | using Xunit; 7 | 8 | namespace Tests; 9 | 10 | public class GLnpUnitTest 11 | { 12 | [Fact] 13 | public void Test1Ops() 14 | { 15 | for (int n = 2; n <= 6; n++) // n = 2, 3, 4, 5 16 | { 17 | for (int p0 = 0; p0 < 5; p0++) // p = 2, 3, 5, 7, 11 18 | { 19 | int p = IntExt.Primes10000[p0]; 20 | 21 | var gl = new GL(n, p); 22 | var rg = Enumerable.Range(0, n * n).ToArray(); 23 | for (int j = 0; j < 5; j++) 24 | { 25 | var mat0 = rg.Select(i => IntExt.Rng.Next(p)).ToArray(); 26 | var mat1 = rg.Select(i => IntExt.Rng.Next(p)).ToArray(); 27 | var det0 = IntExt.AmodP(MatrixExt.ComputeDeterminant(mat0), p); 28 | var det1 = IntExt.AmodP(MatrixExt.ComputeDeterminant(mat1), p); 29 | if (det0 == 0 || det1 == 0) 30 | { 31 | --j; 32 | continue; 33 | } 34 | 35 | var inv0 = MatrixExt.InvertModP(p, mat0); 36 | var inv1 = MatrixExt.InvertModP(p, mat1); 37 | var dot = MatrixExt.DotModP(p, mat0, mat1); 38 | 39 | var e0 = gl.Create(mat0); 40 | var ei0 = gl.Invert(e0); 41 | var f0 = gl.Create(inv0); 42 | var e1 = gl.Create(mat1); 43 | var ei1 = gl.Invert(e1); 44 | var f1 = gl.Create(inv1); 45 | var e2 = gl.Op(e0, e1); 46 | var f2 = gl.Create(dot); 47 | Assert.Equal(det0, gl.Det(e0)); 48 | Assert.Equal(det1, gl.Det(e1)); 49 | Assert.True(inv0.SequenceEqual(ei0.Table)); 50 | Assert.True(inv1.SequenceEqual(ei1.Table)); 51 | Assert.True(dot.SequenceEqual(e2.Table)); 52 | Assert.Equal(f0, ei0); 53 | Assert.Equal(f1, ei1); 54 | Assert.Equal(f2, e2); 55 | } 56 | } 57 | } 58 | } 59 | 60 | [Fact] 61 | public void Test2GL23() 62 | { 63 | var gl = new GL(2, 3); 64 | var a1 = gl[2, 0, 0, 1]; 65 | var b1 = gl[2, 1, 2, 0]; 66 | var g1 = Group.Generate(gl, a1, b1); 67 | Assert.Equal(48, g1.Count()); 68 | Assert.Equal(24, g1.Count(e => IntExt.AmodP(gl.Det(e), 3) == 1)); 69 | Assert.Equal(24, g1.Count(e => IntExt.AmodP(gl.Det(e), 3) == 2)); 70 | 71 | var a2 = gl[1, 1, 0, 1]; 72 | var b2 = gl[0, 1, 2, 0]; 73 | var g2 = Group.Generate(gl, a2, b2); 74 | Assert.Equal(24, g2.Count()); 75 | Assert.Equal(24, g2.Count(e => gl.Det(e) == 1)); 76 | Assert.True(g1.ToHashSet().IsSupersetOf(g2)); 77 | } 78 | 79 | [Fact] 80 | public void Test3GL3p() 81 | { 82 | var gl32 = new GL(3, 2); 83 | var a1 = gl32.At((0, 1, 4, 8), (1, 1, 1, 1)); 84 | var b1 = gl32.At((2, 3, 7), (1, 1, 1)); 85 | var g1 = Group.Generate(gl32, a1, b1); 86 | Assert.Equal(168, g1.Count()); 87 | 88 | var gl33 = new GL(3, 3); 89 | var a2 = gl33.At((0, 4, 8), (2, 1, 1)); 90 | var b2 = gl33.At((0, 2, 3, 7), (2, 1, 2, 2)); 91 | var g2 = Group.Generate(gl33, a2, b2); 92 | Assert.Equal(11232, g2.Count()); 93 | } 94 | } -------------------------------------------------------------------------------- /Tests/GaloisUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using FastGoat.UserGroup; 4 | using Xunit; 5 | 6 | namespace Tests; 7 | 8 | public class GaloisUnitTest 9 | { 10 | [Fact] 11 | public void Test1Ops() 12 | { 13 | foreach (var q in new[] { 2, 4, 8, 3, 9, 27, 5, 25, 125 }) 14 | { 15 | var gf = FG.Galois(q); 16 | Assert.Equal(q - 1, gf.Count()); 17 | foreach (var e1 in gf) 18 | { 19 | var ei = gf.Invert(e1); 20 | Assert.Contains(ei, gf); 21 | var e1ei = gf.Op(e1, ei); 22 | Assert.Equal(gf.Neutral(), e1ei); 23 | foreach (var e2 in gf) 24 | Assert.Contains(gf.Op(e1, e2), gf); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Tests/PermutationUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FastGoat.Commons; 3 | using Xunit; 4 | 5 | namespace Tests; 6 | 7 | public class PermutationUnitTest 8 | { 9 | [Fact] 10 | public void Test1Tuple2Array() 11 | { 12 | Tuple2Array c1 = 1; 13 | Tuple2Array c2 = (2, 1); 14 | Tuple2Array c3 = (2, 3, 5); 15 | Tuple2Array c4 = (2, 3, 4, 5); 16 | Tuple2Array c5 = (8, 6, 2, 3, 5); 17 | Tuple2Array c6 = (2, 9, 3, 1, 5, 4); 18 | Tuple2Array c7 = (2, 8, 6, 11, 3, 5, 0); 19 | Tuple2Array c8 = ((2, 8, 6, 11), (3, 10, 5, 8, 0)); 20 | Tuple2Array c9 = (2, (1, 7), 5); 21 | 22 | Assert.Single(c1.Table); 23 | Assert.Equal(2, c2.Table.Length); 24 | Assert.Equal(3, c3.Table.Length); 25 | Assert.Equal(4, c4.Table.Length); 26 | Assert.Equal(5, c5.Table.Length); 27 | Assert.Equal(6, c6.Table.Length); 28 | Assert.Equal(7, c7.Table.Length); 29 | Assert.Empty(c8.Table); 30 | Assert.Empty(c9.Table); 31 | } 32 | 33 | [Fact] 34 | public void Test2Permutation2Cycles() 35 | { 36 | var p1 = IntExt.PermutationToCycles(2, new[] { 0, 1 }); 37 | Assert.Equal(2, p1.Length); 38 | Assert.Equal(0, p1[0][0]); 39 | Assert.Equal(1, p1[1][0]); 40 | 41 | var p2 = IntExt.PermutationToCycles(2, new[] { 1, 0 }); 42 | Assert.Single(p2); 43 | Assert.Equal(0, p2[0][0]); 44 | Assert.Equal(1, p2[0][1]); 45 | 46 | var p3 = IntExt.PermutationToCycles(5, new[] { 2, 0, 1, 3, 4 }); 47 | Assert.True(p3[0].SequenceEqual(new[] { 0, 2, 1 })); 48 | Assert.True(p3[1].SequenceEqual(new[] { 3 })); 49 | Assert.True(p3[2].SequenceEqual(new[] { 4 })); 50 | 51 | var p4 = IntExt.PermutationToCycles(5, new[] { 2, 3, 4, 1, 0 }); 52 | Assert.True(p4[0].SequenceEqual(new[] { 0, 2, 4 })); 53 | Assert.True(p4[1].SequenceEqual(new[] { 1, 3 })); 54 | 55 | var p5 = IntExt.PermutationToCycles(5, new[] { 2, 3, 4, 3, 0 }); 56 | Assert.Empty(p5); 57 | 58 | var p6 = IntExt.PermutationToCycles(0, new[] { 2, 3, 4, 3, 0 }); 59 | Assert.Empty(p6); 60 | } 61 | 62 | [Fact] 63 | public void Test3PermutationsOperations() 64 | { 65 | var p1 = new[] { 1, 0, 3, 2 }; 66 | var p2 = new[] { 2, 0, 1, 3 }; 67 | var p3 = new[] { 1, 2, 0, 3 }; 68 | var p4 = new[] { 0, 2, 3, 1 }; 69 | var c = new[] { 0, 0, 0, 0 }; 70 | 71 | IntExt.InvertPermutation(p1, c); 72 | Assert.True(p1.SequenceEqual(c)); 73 | 74 | IntExt.InvertPermutation(p2, c); 75 | Assert.True(p3.SequenceEqual(c)); 76 | 77 | IntExt.ComposePermutation(p1, p2, c); 78 | Assert.True(p4.SequenceEqual(c)); 79 | 80 | c = new[] { 0, 1, 2, 3 }; 81 | IntExt.ApplyCycle(c, new[] { 2, 1, 0 }); 82 | Assert.True(p2.SequenceEqual(c)); 83 | IntExt.ApplyCycle(c, new[] { 0, 1 }); 84 | IntExt.ApplyCycle(c, new[] { 3, 2 }); 85 | Assert.True(p4.SequenceEqual(c)); 86 | } 87 | 88 | [Fact] 89 | public void Test4AllPermutations() 90 | { 91 | Assert.Equal(6, IntExt.GetPermutations(3).Length); 92 | Assert.Equal(24, IntExt.GetPermutations(4).Length); 93 | Assert.Equal(120, IntExt.GetPermutations(5).Length); 94 | Assert.Equal(720, IntExt.GetPermutations(6).Length); 95 | Assert.Equal(5040, IntExt.GetPermutations(7).Length); 96 | Assert.Equal(40320, IntExt.GetPermutations(8).Length); 97 | } 98 | 99 | [Fact] 100 | public void Test5ComposeCycles() 101 | { 102 | var t0 = Tuple2Array.ComplexTuples((1, 2, 3, 4, 5)); 103 | var t1 = Tuple2Array.ComplexTuples(((1, 2), (3, 4, 5))); 104 | var t2 = Tuple2Array.ComplexTuples(((1), (2, 3, 4))); 105 | var t3 = Tuple2Array.ComplexTuples(((1, 5), ((2, 3), (4, 6, 7)))); 106 | 107 | Assert.Single(t0); 108 | 109 | Assert.Equal(2, t1.Length); 110 | Assert.Equal(2, t1[0].Table.Length); 111 | Assert.Equal(3, t1[1].Table.Length); 112 | 113 | Assert.Equal(2, t2.Length); 114 | Assert.Single(t2[0].Table); 115 | Assert.Equal(3, t2[1].Table.Length); 116 | 117 | Assert.Single(t3); 118 | Assert.Equal(2, t3[0].Table.Length); 119 | } 120 | } -------------------------------------------------------------------------------- /Tests/SemiDirectProdUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FastGoat.Structures.CartesianProduct; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Integers; 5 | using FastGoat.UserGroup.Perms; 6 | using Xunit; 7 | 8 | namespace Tests; 9 | 10 | public class SemiDirectProdUnitTest 11 | { 12 | [Fact] 13 | public void Test1ThrowException() 14 | { 15 | var z3 = new Zn(3); 16 | var g3 = Group.Generate(z3, z3[1]); 17 | Assert.Throws(() => Group.SemiDirectProd(g3, g3)); 18 | } 19 | 20 | [Fact] 21 | public void Test2SemiDirectProduct() 22 | { 23 | var g2 = Group.Generate(new Zn(2), new Zn(2)[1]); 24 | var g3 = Group.Generate(new Zn(3), new Zn(3)[1]); 25 | var g4 = Group.Generate(new Zn(4), new Zn(4)[1]); 26 | var d3 = Group.SemiDirectProd(g3, g2); 27 | var d4 = Group.SemiDirectProd("D4", g4, g2); 28 | 29 | var s3 = new Sn(3); 30 | var g6 = Group.Generate(s3, s3[(1, 2)], s3[(1, 2, 3)]); 31 | Assert.True(d3.IsIsomorphicTo(g6)); 32 | Assert.Equal("D4", d4.Name); 33 | } 34 | 35 | [Fact] 36 | public void Test3ComplexSemiDirectProduct() 37 | { 38 | var g1 = Group.SemiDirectProd(Product.Generate(new Cn(3), new Cn(3)), new Cn(2)); 39 | Assert.Equal(GroupType.NonAbelianGroup, g1.GroupType); 40 | Assert.Equal(18, g1.Count()); 41 | Assert.True(Group.IsGroup(g1)); 42 | 43 | var g2 = Group.SemiDirectProd(new Cn(8), Product.Generate(new Cn(2), new Cn(2))); 44 | Assert.Equal(GroupType.NonAbelianGroup, g2.GroupType); 45 | Assert.Equal(32, g2.Count()); 46 | Assert.True(Group.IsGroup(g2)); 47 | 48 | var g3 = Group.SemiDirectProd(Product.Generate(new Cn(2), new Cn(2), new Cn(2)), 49 | Product.Generate(new Cn(2), new Cn(2))); 50 | Assert.Equal(GroupType.NonAbelianGroup, g3.GroupType); 51 | Assert.Equal(32, g3.Count()); 52 | Assert.True(Group.IsGroup(g3)); 53 | 54 | var g4 = Group.SemiDirectProd(new Cn(3), new Cn(8)); 55 | var g5 = Group.SemiDirectProd(g4, new Cn(2)); 56 | Assert.Equal(GroupType.NonAbelianGroup, g5.GroupType); 57 | Assert.Equal(48, g5.Count()); 58 | Assert.True(Group.IsGroup(g5)); 59 | } 60 | } -------------------------------------------------------------------------------- /Tests/SnUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Perms; 5 | using Xunit; 6 | 7 | namespace Tests; 8 | 9 | public class SnUnitTest 10 | { 11 | [Fact] 12 | public void Test1ThrowException() 13 | { 14 | var s3 = new Sn(3); 15 | var e1 = s3.Neutral(); 16 | var s4 = new Sn(4); 17 | var e2 = s4.Neutral(); 18 | Assert.Throws(() => new Sn(-5)); 19 | Assert.Throws(() => s4.Invert(e1)); 20 | Assert.Throws(() => s3.Op(e1, e2)); 21 | Assert.Throws(() => e1.CompareTo(e2)); 22 | Assert.Throws(() => s3.Times(e2, 3)); 23 | Assert.Throws(() => s4[(4, 3, 4)]); 24 | Assert.Throws(() => s4[(2, 6)]); 25 | Assert.Throws(() => s4[(2, 1), 3]); 26 | Assert.Throws(() => s4[((2, 1), (3, 4))]); 27 | } 28 | 29 | [Fact] 30 | public void Test2Create() 31 | { 32 | var s4 = new Sn(4); 33 | var e1 = s4[(1, 2)]; 34 | var e2 = s4[(1, 3), (2, 4)]; 35 | var e3 = s4[(1, 2, 4)]; 36 | var e4 = s4[(4, 2, 1)]; 37 | Assert.True(e1.Table.SequenceEqual(new[] { 1, 0, 2, 3 })); 38 | Assert.True(e2.Table.SequenceEqual(new[] { 2, 3, 0, 1 })); 39 | Assert.Equal(e1, s4.Invert(e1)); 40 | Assert.Equal(e3, s4.Invert(e4)); 41 | Assert.Equal(s4[(1, 4)], s4.Op(e1, e3)); 42 | Assert.Equal(e4, s4.Times(e3, 2)); 43 | Assert.Equal(s4.Neutral(), s4.Times(e3, -6)); 44 | Assert.Equal(s4, e3.BaseGroup); 45 | } 46 | 47 | [Fact] 48 | public void Test3AllElements() 49 | { 50 | var s3 = new Sn(3); 51 | var s4 = new Sn(4); 52 | var s5 = new Sn(5); 53 | var s6 = new Sn(6); 54 | var s7 = new Sn(7); 55 | 56 | var S3 = Group.Generate(s3, s3[(1, 2)], s3[(1, 2, 3)]).ToHashSet(); 57 | var S4 = Group.Generate(s4, s4[(1, 2)], s4[(1, 2, 3, 4)]).ToHashSet(); 58 | var S5 = Group.Generate(s5, s5[(1, 2)], s5[(1, 2, 3, 4, 5)]).ToHashSet(); 59 | var S6 = Group.Generate(s6, s6[(1, 2)], s6[(1, 2, 3, 4, 5, 6)]).ToHashSet(); 60 | var S7 = Group.Generate(s7, s7[(1, 2)], s7[(1, 2, 3, 4, 5, 6, 7)]).ToHashSet(); 61 | 62 | Assert.True(S3.SetEquals(IntExt.GetPermutations(3).Select(s3.CreateElement))); 63 | Assert.True(S4.SetEquals(IntExt.GetPermutations(4).Select(s4.CreateElement))); 64 | Assert.True(S5.SetEquals(IntExt.GetPermutations(5).Select(s5.CreateElement))); 65 | Assert.True(S6.SetEquals(IntExt.GetPermutations(6).Select(s6.CreateElement))); 66 | Assert.True(S7.SetEquals(IntExt.GetPermutations(7).Select(s7.CreateElement))); 67 | } 68 | 69 | [Fact] 70 | public void Test4InfixOperators() 71 | { 72 | var s3 = new Sn(3); 73 | Assert.True(s3[(1, 2)] == s3[(2, 1)]); 74 | Assert.True(s3[(1, 2)] != s3[(1, 3)]); 75 | Assert.False(s3[(1, 2)] != s3[(2, 1)]); 76 | Assert.False(s3[(1, 2)] == s3[(1, 3)]); 77 | Assert.Equal(s3[(1, 2, 3)], s3[(1, 2)] * s3[(1, 3)]); 78 | Assert.Equal(s3.Neutral(), s3[(1, 2, 3)] ^ 3); 79 | } 80 | 81 | [Fact] 82 | public void Test5Symm() 83 | { 84 | var s3 = new Symm(3); 85 | Assert.Contains(new[] 86 | { 87 | s3.Neutral(), 88 | s3[(1, 2)], s3[(1, 3)], s3[(2, 3)], 89 | s3[(1, 2, 3)], s3[(1, 3, 2)] 90 | } 91 | , s3.Contains 92 | ); 93 | Assert.Equal(2, s3.TransitiveSubGroups().Count()); 94 | } 95 | } -------------------------------------------------------------------------------- /Tests/StaticExtUnittest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using FastGoat.Commons; 4 | using FastGoat.Structures; 5 | using FastGoat.UserGroup; 6 | using FastGoat.UserGroup.Integers; 7 | using FastGoat.UserGroup.Polynoms; 8 | using Xunit; 9 | 10 | namespace Tests; 11 | 12 | public class StaticExtUnittest 13 | { 14 | [Fact] 15 | public void Test1Matrix() 16 | { 17 | for (int n = 2; n < 6; n++) 18 | { 19 | var p = IntExt.Rng.Next(2, 10); 20 | var diag0 = MatrixExt.Diagonal(n, p); 21 | var diag1 = Enumerable.Range(0, n * n).Select(i => i % (n + 1) == 0 ? p : 0).ToArray(); 22 | Assert.True(diag0.SequenceEqual(diag1)); 23 | 24 | var rg = Enumerable.Range(0, n * n).ToArray(); 25 | for (int k = 0; k < 5; k++) 26 | { 27 | var mat = rg.Select(i => IntExt.Rng.Next(p)).ToArray(); 28 | var det = MatrixExt.ComputeDeterminant(mat); 29 | var com = MatrixExt.Comatrix(mat); 30 | var tcom = MatrixExt.Transpose(com); 31 | var dot = MatrixExt.Dot(tcom, mat); 32 | Assert.True(dot.SequenceEqual(MatrixExt.Diagonal(n, det))); 33 | } 34 | } 35 | } 36 | 37 | [Fact] 38 | public void Test2BezoutGcd() 39 | { 40 | var zn = new Zn(3 * 5 * 17); 41 | var seq = Group.Generate(zn, zn[3]).Grid2D(Group.Generate(zn, zn[5])); 42 | 43 | bool TestBz(int a, int b) 44 | { 45 | var d = IntExt.Gcd(a, b); 46 | var (x, y) = IntExt.Bezout(a, b); 47 | return d >= 0 && d == a * x + b * y; 48 | } 49 | 50 | Assert.True(seq.Where(e => !e.t1.IsZero() && !e.t2.IsZero()).All(e => TestBz(e.t1.K, e.t2.K))); 51 | } 52 | 53 | [Fact] 54 | public void Test3FpPolynom() 55 | { 56 | var x = FG.ZPoly(5); 57 | var a0 = (x + 1) * (x + 2); 58 | var a1 = (x + 1) * (x + 3); 59 | var a2 = (x + 2) * (x + 3); 60 | var a3 = (x + 1) * (x + 2) * (x + 3); 61 | 62 | var q0 = a3 / (x + 1); 63 | var q1 = a3 / (x + 2); 64 | var q2 = a3 / (x + 3); 65 | Assert.Equal(q0, a2); 66 | Assert.Equal(q1, a1); 67 | Assert.Equal(q2, a0); 68 | 69 | var x4 = x + 4; 70 | var qr = a3.Div(x4); 71 | Assert.Equal(a3, qr.quo * x4 + qr.rem); 72 | } 73 | 74 | [Fact] 75 | public void Test4FpBezout() 76 | { 77 | var x = FG.ZPoly(7); 78 | var a = x * x + 3 * x; 79 | var b = x.Pow(4) + x * x; 80 | var gcd = Ring.Gcd(a, b); 81 | var (x0, y0) = Ring.Bezout(a, b); 82 | Assert.Equal(gcd, a * x0 + b * y0); 83 | } 84 | 85 | [Fact] 86 | public void Test5MatrixPivotRREF() 87 | { 88 | for (int n = 2; n < 6; n++) 89 | { 90 | var p = IntExt.Primes10000[IntExt.Rng.Next(12)]; 91 | var id = MatrixExt.Identity(n); 92 | 93 | var rg = Enumerable.Range(0, n * n).ToArray(); 94 | for (int k = 0; k < 5; k++) 95 | { 96 | var mat = rg.Select(_ => IntExt.Rng.Next(p)).ToArray(); 97 | var det0 = MatrixExt.ComputeDeterminant(mat); 98 | var det1 = MatrixExt.DeterminantByPivot(n, p, mat); 99 | Assert.True(IntExt.AmodP(det0, p) == det1); 100 | if (det1 == 0) 101 | { 102 | --k; 103 | continue; 104 | } 105 | 106 | var inv = MatrixExt.InversionByRREF(n, p, mat); 107 | var dot = MatrixExt.ModP(p, MatrixExt.Dot(inv, mat)); 108 | Assert.True(id.SequenceEqual(dot)); 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | 7 | false 8 | 9 | default 10 | 11 | Debug;Release 12 | 13 | AnyCPU;x64 14 | 15 | 16 | 17 | x64 18 | false 19 | none 20 | 21 | 22 | 23 | 24 | 25 | 26 | runtime; build; native; contentfiles; analyzers; buildtransitive 27 | all 28 | 29 | 30 | runtime; build; native; contentfiles; analyzers; buildtransitive 31 | all 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tests/ToddCoxeterUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FastGoat.Commons; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Words; 5 | using FastGoat.UserGroup.Words.Tools; 6 | using Xunit; 7 | 8 | namespace Tests; 9 | 10 | public class ToddCoxeterUnitTest 11 | { 12 | [Fact] 13 | public void Test1Cyclic() 14 | { 15 | var ta5 = Graph.Run("a5"); 16 | var gens = ta5.Generators().ToArray(); 17 | var words = ta5.Words().Select(e => e.Glue()).ToArray(); 18 | Assert.Single(gens); 19 | Assert.Equal('a', gens[0]); 20 | Assert.Contains(new[] { "", "a", "aa", "aaa", "A" }, words.Contains); 21 | Assert.Equal("aa", ta5.Rewrite("aaaAaaaAaaa")); 22 | } 23 | 24 | [Fact] 25 | public void Test2Klein() 26 | { 27 | var klein = Graph.Run("a2, b2, ab = ba"); 28 | var gens = klein.Generators().ToArray(); 29 | var words = klein.Words().Select(e => e.Glue()).ToArray(); 30 | Assert.Contains(new[] { 'a', 'b' }, gens.Contains); 31 | Assert.Contains(new[] { "", "a", "b", "ab" }, words.Contains); 32 | Assert.Equal("ab", klein.Rewrite("ababAbbaAb").Glue()); 33 | } 34 | 35 | [Fact] 36 | public void Test3H21() 37 | { 38 | var h21 = Graph.Run("a7, b3, a2=bab-1"); 39 | var gens = h21.Generators().ToArray(); 40 | var words = h21.Words().Select(e => e.Glue()).ToArray(); 41 | Assert.Contains(new[] { 'a', 'b' }, gens.Contains); 42 | Assert.Equal(21, words.Length); 43 | } 44 | 45 | [Fact] 46 | public void Test4Abelian() 47 | { 48 | var ab = Graph.Run("a4, b3, c2, ab=ba, ac=ca, bc=cb"); 49 | var gens = ab.Generators().ToArray(); 50 | var words = ab.Words().Select(e => e.Glue()).ToArray(); 51 | Assert.Contains(new[] { 'a', 'b', 'c' }, gens.Contains); 52 | Assert.Equal(24, words.Length); 53 | } 54 | 55 | [Fact] 56 | public void Test5F20() 57 | { 58 | var f20 = Graph.Run("a5, b4, abababab, a2ba-1b-1"); 59 | var gens = f20.Generators().ToArray(); 60 | var words = f20.Words().Select(e => e.Glue()).ToArray(); 61 | Assert.Contains(new[] { 'a', 'b' }, gens.Contains); 62 | Assert.Equal(20, words.Length); 63 | } 64 | 65 | [Fact] 66 | public void Test6WordGroup() 67 | { 68 | var wg = new WordGroup("a12, b2=a6, bab-1=a-1"); 69 | var w = wg["bababa"]; 70 | Assert.Equal(24, wg.Count()); 71 | Assert.Equal(GroupType.NonAbelianGroup, wg.GroupType); 72 | Assert.Equal("AB", w.Get()); 73 | } 74 | } -------------------------------------------------------------------------------- /Tests/UserGroupUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FastGoat.Structures; 3 | using FastGoat.UserGroup; 4 | using Xunit; 5 | 6 | namespace Tests; 7 | 8 | public class UserGroupUnitTest 9 | { 10 | [Fact] 11 | public void Test1Dihedral() 12 | { 13 | for (int n = 3; n <= 8; n++) 14 | { 15 | var dn0 = FG.Dihedral(n); 16 | var dn1 = FG.DihedralSdp(n); 17 | var dn2 = FG.DihedralWg(n); 18 | Assert.True(dn1.IsIsomorphicTo(dn0)); 19 | Assert.True(dn1.IsIsomorphicTo(dn2)); 20 | } 21 | } 22 | 23 | [Fact] 24 | public void Test2Alternate() 25 | { 26 | Assert.Equal(3, FG.Alternate(3).Count()); 27 | Assert.Equal(6, FG.Symmetric(3).Count()); 28 | 29 | Assert.Equal(12, FG.Alternate(4).Count()); 30 | Assert.Equal(24, FG.Symmetric(4).Count()); 31 | 32 | Assert.Equal(60, FG.Alternate(5).Count()); 33 | Assert.Equal(120, FG.Symmetric(5).Count()); 34 | 35 | Assert.Equal(360, FG.Alternate(6).Count()); 36 | Assert.Equal(720, FG.Symmetric(6).Count()); 37 | } 38 | 39 | [Fact] 40 | public void Test3Abelian() 41 | { 42 | Assert.Equal(9, FG.Abelian(3, 3).Count()); 43 | Assert.Equal(150, FG.Abelian(10, 15).Count()); 44 | Assert.Equal(180, FG.Abelian(3, 6, 10).Count()); 45 | Assert.Equal("H1", FG.Abelian("H1", 3, 5).Name); 46 | Assert.Equal("K2", FG.Abelian("K2", 7, 11, 15).Name); 47 | } 48 | 49 | [Fact] 50 | public void Test4PermGroup() 51 | { 52 | Assert.Equal(4, FG.PermGroup(4, ((1, 2), (3, 4)), ((1, 3), (2, 4))).Count()); 53 | Assert.Equal(8, FG.PermGroup(4, (1, 2), ((1, 3), (2, 4))).Count()); 54 | Assert.Equal(12, FG.PermGroup(4, ((1, 2), (3, 4)), (1, 2, 3)).Count()); 55 | Assert.Equal("S3", FG.PermGroup("S3", 3, (1, 2), (1, 2, 3)).Name); 56 | } 57 | 58 | [Fact] 59 | public void Test5Frobenius() 60 | { 61 | var f20 = FG.Frobenius(20); 62 | Assert.Equal(2, f20.Count); 63 | Assert.Equal(20, f20[0].Count()); 64 | Assert.Equal(20, f20[1].Count()); 65 | 66 | var f20sdp = FG.FrobeniusSdp(20); 67 | Assert.True(f20[0].IsIsomorphicTo(f20sdp[0])); 68 | Assert.True(f20[1].IsIsomorphicTo(f20sdp[1])); 69 | 70 | var f21 = FG.Frobenius(21); 71 | Assert.Single(f21); 72 | Assert.Equal(21, f21[0].Count()); 73 | 74 | var f21sdp = FG.FrobeniusSdp(21); 75 | Assert.True(f21[0].IsIsomorphicTo(f21sdp[0])); 76 | } 77 | 78 | [Fact] 79 | public void Test6DiCyclic() 80 | { 81 | var d2 = FG.DiCyclic(2); 82 | var d2sdp = FG.DiCyclicSdp(2); 83 | var d2gl = FG.DicyclicGL2p(2); 84 | Assert.Equal(8, d2.Count()); 85 | Assert.True(d2.IsIsomorphicTo(d2sdp)); 86 | Assert.True(d2.IsIsomorphicTo(d2gl)); 87 | 88 | var d3 = FG.DiCyclic(3); 89 | var d3sdp = FG.DiCyclicSdp(3); 90 | var d3gl = FG.DicyclicGL2p(3); 91 | Assert.Equal(12, d3.Count()); 92 | Assert.True(d3.IsIsomorphicTo(d3sdp)); 93 | Assert.True(d3.IsIsomorphicTo(d3gl)); 94 | 95 | var d5 = FG.DiCyclic(5); 96 | var d5sdp = FG.DiCyclicSdp(5); 97 | var d5gl = FG.DicyclicGL2p(5); 98 | Assert.Equal(20, d5.Count()); 99 | Assert.True(d5.IsIsomorphicTo(d5sdp)); 100 | Assert.True(d5.IsIsomorphicTo(d5gl)); 101 | } 102 | 103 | [Fact] 104 | public void Test7SemiDihedral() 105 | { 106 | for (int n = 3; n <= 6; n++) 107 | { 108 | var qd = FG.SemiDihedral(n); 109 | var qdSdp = FG.SemiDihedralSdp(n); 110 | var order = 1 << n; 111 | Assert.Equal(order, qd.Count()); 112 | Assert.True(qdSdp.IsIsomorphicTo(qd)); 113 | 114 | var mm = FG.ModularMax(n); 115 | var mmsdp = FG.ModularMaxSdp(n); 116 | Assert.Equal(order, mm.Count()); 117 | Assert.True(mmsdp.IsIsomorphicTo(mm)); 118 | Assert.False(mmsdp.IsIsomorphicTo(qdSdp)); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Tests/ZnCGroupUnitTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Xunit; 3 | using FastGoat.Structures.CartesianProduct; 4 | using FastGoat.Structures; 5 | using FastGoat.UserGroup.Integers; 6 | 7 | namespace Tests; 8 | 9 | public class ZnCGroupUnitTest 10 | { 11 | [Fact] 12 | public void Test1GenerateElement() 13 | { 14 | var zn = new Zn(30); 15 | var g1 = Group.GenerateElements(zn, zn[6]); 16 | var g2 = Group.GenerateElements(zn, zn[10]); 17 | var g3 = Group.GenerateElements(zn, zn[6], zn[10]); 18 | Assert.Equal(5, g1.Count()); 19 | Assert.Equal(3, g2.Count()); 20 | Assert.Equal(15, g3.Count()); 21 | } 22 | 23 | [Fact] 24 | public void Test2Cycle() 25 | { 26 | var zn = new Zn(8); 27 | var cycle = Group.Cycle(zn, zn[2]); 28 | Assert.Equal(4, cycle.Count); 29 | Assert.Equal(4, cycle[zn[0]]); 30 | Assert.Equal(1, cycle[zn[2]]); 31 | Assert.Equal(2, cycle[zn[4]]); 32 | Assert.Equal(3, cycle[zn[6]]); 33 | } 34 | 35 | [Fact] 36 | public void Test3ConcreteGroup() 37 | { 38 | var zn = new Zn(40); 39 | var g0 = Group.Generate(zn, zn[1]); 40 | var g1 = Group.Generate(g0, zn[10]); 41 | var g2 = Group.Generate(g0, zn[8]); 42 | var g3 = Group.Create(Product.Group(g1, g2)); 43 | var g4 = Group.Generate(g0, zn[2]); 44 | var g5 = Group.DirectProduct(g1, g2); 45 | Assert.Equal(40, g0.Count()); 46 | Assert.Equal(4, g1.Count()); 47 | Assert.Equal(5, g2.Count()); 48 | Assert.Equal(20, g3.Count()); 49 | Assert.Equal(20, g4.Count()); 50 | Assert.Equal(20, g5.Count()); 51 | Assert.Equal(GroupType.AbelianGroup, g0.GroupType); 52 | Assert.Equal(GroupType.AbelianGroup, g1.GroupType); 53 | Assert.True(g3.IsIsomorphicTo(g4)); 54 | Assert.True(g3.IsIsomorphicTo(g5)); 55 | } 56 | } -------------------------------------------------------------------------------- /Tests/ZnQuotientUnitTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using FastGoat.Structures.CartesianProduct; 3 | using FastGoat.Structures; 4 | using FastGoat.UserGroup.Integers; 5 | using FastGoat.UserGroup.Perms; 6 | 7 | namespace Tests; 8 | 9 | public class ZnQuotientUnitTest 10 | { 11 | [Fact] 12 | public void Test1Cosets() 13 | { 14 | var g0 = Group.Generate(new Zn(2), new Zn(2)[1]); 15 | var h0 = Product.Group(g0, g0, g0); 16 | var h1 = Group.Create("H", h0); 17 | var h2 = Group.Generate("K", h1, h1[1, 0, 0]); 18 | var cosets = Group.Cosets(h1, h2); 19 | Assert.Equal(8, cosets.Count); 20 | 21 | var c000 = cosets[h1[0, 0, 0]]; 22 | Assert.Equal(c000.X, h1[0, 0, 0]); 23 | Assert.Equal(c000, cosets[h1[1, 0, 0]]); 24 | 25 | var c010 = cosets[h1[0, 1, 0]]; 26 | Assert.Equal(c010.X, h1[0, 1, 0]); 27 | Assert.Equal(c010, cosets[h1[1, 1, 0]]); 28 | 29 | var c001 = cosets[h1[0, 0, 1]]; 30 | Assert.Equal(c001.X, h1[0, 0, 1]); 31 | Assert.Equal(c001, cosets[h1[1, 0, 1]]); 32 | 33 | var c011 = cosets[h1[0, 1, 1]]; 34 | Assert.Equal(c011.X, h1[0, 1, 1]); 35 | Assert.Equal(c011, cosets[h1[1, 1, 1]]); 36 | } 37 | 38 | [Fact] 39 | public void Test2QuotientGroup() 40 | { 41 | var g0 = Group.Generate(new Zn(2), new Zn(2)[1]); 42 | var klein = Group.Create(Product.Group(g0, g0)); 43 | var h0 = Product.Group(new Zn(4), new Zn(10)); 44 | var h1 = Group.Generate("H", h0, h0[1, 0], h0[0, 1]); 45 | var h2 = Group.Generate("K", h1, h1[2, 2]); 46 | var hQuo = h1.Over(h2); 47 | Assert.True(hQuo.IsIsomorphicTo(klein)); 48 | } 49 | 50 | [Fact] 51 | public void Test3ThrowException() 52 | { 53 | var z40 = new Zn(40); 54 | var g40 = Group.Generate(z40, z40[1]); 55 | var g20 = Group.Generate(g40, g40[2]); 56 | var g8 = Group.Generate(g40, g40[5]); 57 | Assert.Throws(() => g20.Over(g8)); 58 | 59 | var s4 = new Sn(4); 60 | var g24 = Group.Generate(s4, s4[(1, 2)], s4[(1, 2, 3, 4)]); 61 | var g3 = Group.Generate(s4, s4[(1, 2, 3)]); 62 | Assert.Throws(() => g24.Over(g3)); 63 | } 64 | } -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: Fast Goat 🐐 for Finite Groups 2 | author: 3 | name: "@aidevnn" 4 | baseurl: "/FastGoat" # the subpath of your site, e.g. /blog 5 | url: "https::/aidenn.github.io" # the base hostname & protocol for your site, e.g. http://example.com 6 | 7 | # Build settings 8 | theme: minima 9 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {%- include head.html -%} 5 | 6 | 7 | 8 | {%- include header.html -%} 9 | 10 |
11 |
12 | {{ content }} 13 |
14 |
15 | 16 | {%- include footer.html -%} 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidevnn/FastGoat/619188c32e5c386270dc012e9f6559b33ad14b36/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # Feel free to add content and custom Front Matter to this file. 3 | # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults 4 | 5 | layout: default 6 | --- 7 | 8 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } --------------------------------------------------------------------------------