GroupsMath 0.5.0__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GroupsMath
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: The educational Python library for Group Theory
5
5
  Author-email: Mario Sultan Romero <mariosultan.uem@gmail.com>
6
6
  License: PolyForm Strict License 1.0.0.
@@ -20,16 +20,27 @@ Requires-Dist: matplotlib>=3.0.0
20
20
  Requires-Dist: numpy>=1.20.0
21
21
  Dynamic: license-file
22
22
 
23
- # GroupsMath – v0.5.0
23
+ # GroupsMath – v0.6.0
24
+
25
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/groupsmath)](https://pypistats.org/packages/groupsmath)
26
+ [![PyPI Version](https://img.shields.io/pypi/v/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
27
+ [![Python Versions](https://img.shields.io/pypi/pyversions/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
28
+ ![Last Commit](https://img.shields.io/github/last-commit/MarioSultan/groupsmath?color=2A646E)
29
+ ![coverage](https://img.shields.io/badge/road%20to%20v1.0.0-85%25-yellowgreen?color=2A646E)
30
+ <!-- ![GitHub Stars](https://img.shields.io/github/stars/MarioSultan/groupsmath?style=social) -->
31
+
24
32
 
25
33
  ![GroupsMath Logo](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/logo.png)
26
34
 
27
35
 
28
36
  **GroupsMath** is a Python module for constructing, studying, and manipulating finite and infinite groups.
29
37
 
30
- The project aims to provide a simple and intuitive interface for working with finite groups and their algebraic properties.
38
+ The project aims to provide a **simple** and **intuitive** interface for working with groups and their algebraic properties.
39
+
40
+ ![Examples](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/imgs/examples.png)
41
+
42
+ > **⚠️ Notice:** Version v1.0.0 is nearing its official release.
31
43
 
32
- > **Note:** GroupsMath is currently under active development. Its API is still evolving and may change before version `1.0.0`.
33
44
 
34
45
  ---
35
46
 
@@ -51,7 +62,7 @@ or visit https://github.com/MarioSultan/GroupsMath and download all the files.
51
62
 
52
63
  ---
53
64
 
54
- ## Examples
65
+ ## Quick start
55
66
 
56
67
  ### A program in GroupsMath
57
68
  ```python
@@ -102,14 +113,18 @@ GroupsMath is designed to provide tools for working with finite (and infinite) g
102
113
  * Determination of the order of a group and its elements.
103
114
  * Operation with group elements (multiplication, inverse, powers, ...)
104
115
  * Computation of Cayley tables with `matplotlib.pyplot`.
105
- * Detection of algebraic properties such as cyclicity and commutativity.
116
+ * Detection of algebraic properties such as cyclicity, commutativity and solubility.
117
+ * Centralizers, conjugacy classes and conmutator.
106
118
  * Computation and exploration of other structural properties of finite groups.
107
119
  * Predefined group families in the library `groupsmath.precooked`, such as $C_n$, $S_n$, $A_n$, $D_n$, $V_4$, $Q_8$, ...
120
+ * Isomorphisms between groups.
108
121
 
109
122
  **SUBGROUPS:**
110
123
  * Study of subgroups (order, cosets, normal subgroups, quotients, ...).
111
124
  * Normal subgroups.
112
125
  * Quotient groups $Q=G/H$.
126
+ * Conmutator and derived subgroups $G'$.
127
+ * Abelianization $G/G'$
113
128
 
114
129
  **AUTOMORPHISMS:**
115
130
  * Class `Automorphism` and automorphism functions.
@@ -138,6 +153,7 @@ The GroupsMath team is currently working on theese ideas:
138
153
  * Representation theory.
139
154
  * and much more...
140
155
 
156
+
141
157
  ---
142
158
 
143
159
  ## Documentation
@@ -146,14 +162,6 @@ Detailed documentation is available in the [`docs`](https://github.com/MarioSult
146
162
 
147
163
  ---
148
164
 
149
- ## Project status
150
-
151
- GroupsMath is currently under active development.
152
-
153
- The project has successfully transitioned to an object-oriented interface centered around the `Group` class. The legacy function-based interface is being removed for future versions. The API should therefore be considered unstable until the `1.0.0` release, and breaking changes may occur between development versions.
154
-
155
- ---
156
-
157
165
  ## Contributing
158
166
 
159
167
  Contributions, suggestions, and bug reports are welcome. If you find a bug or have an idea for improving GroupsMath, please open an issue in the GitHub repository.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GroupsMath
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: The educational Python library for Group Theory
5
5
  Author-email: Mario Sultan Romero <mariosultan.uem@gmail.com>
6
6
  License: PolyForm Strict License 1.0.0.
@@ -20,16 +20,27 @@ Requires-Dist: matplotlib>=3.0.0
20
20
  Requires-Dist: numpy>=1.20.0
21
21
  Dynamic: license-file
22
22
 
23
- # GroupsMath – v0.5.0
23
+ # GroupsMath – v0.6.0
24
+
25
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/groupsmath)](https://pypistats.org/packages/groupsmath)
26
+ [![PyPI Version](https://img.shields.io/pypi/v/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
27
+ [![Python Versions](https://img.shields.io/pypi/pyversions/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
28
+ ![Last Commit](https://img.shields.io/github/last-commit/MarioSultan/groupsmath?color=2A646E)
29
+ ![coverage](https://img.shields.io/badge/road%20to%20v1.0.0-85%25-yellowgreen?color=2A646E)
30
+ <!-- ![GitHub Stars](https://img.shields.io/github/stars/MarioSultan/groupsmath?style=social) -->
31
+
24
32
 
25
33
  ![GroupsMath Logo](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/logo.png)
26
34
 
27
35
 
28
36
  **GroupsMath** is a Python module for constructing, studying, and manipulating finite and infinite groups.
29
37
 
30
- The project aims to provide a simple and intuitive interface for working with finite groups and their algebraic properties.
38
+ The project aims to provide a **simple** and **intuitive** interface for working with groups and their algebraic properties.
39
+
40
+ ![Examples](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/imgs/examples.png)
41
+
42
+ > **⚠️ Notice:** Version v1.0.0 is nearing its official release.
31
43
 
32
- > **Note:** GroupsMath is currently under active development. Its API is still evolving and may change before version `1.0.0`.
33
44
 
34
45
  ---
35
46
 
@@ -51,7 +62,7 @@ or visit https://github.com/MarioSultan/GroupsMath and download all the files.
51
62
 
52
63
  ---
53
64
 
54
- ## Examples
65
+ ## Quick start
55
66
 
56
67
  ### A program in GroupsMath
57
68
  ```python
@@ -102,14 +113,18 @@ GroupsMath is designed to provide tools for working with finite (and infinite) g
102
113
  * Determination of the order of a group and its elements.
103
114
  * Operation with group elements (multiplication, inverse, powers, ...)
104
115
  * Computation of Cayley tables with `matplotlib.pyplot`.
105
- * Detection of algebraic properties such as cyclicity and commutativity.
116
+ * Detection of algebraic properties such as cyclicity, commutativity and solubility.
117
+ * Centralizers, conjugacy classes and conmutator.
106
118
  * Computation and exploration of other structural properties of finite groups.
107
119
  * Predefined group families in the library `groupsmath.precooked`, such as $C_n$, $S_n$, $A_n$, $D_n$, $V_4$, $Q_8$, ...
120
+ * Isomorphisms between groups.
108
121
 
109
122
  **SUBGROUPS:**
110
123
  * Study of subgroups (order, cosets, normal subgroups, quotients, ...).
111
124
  * Normal subgroups.
112
125
  * Quotient groups $Q=G/H$.
126
+ * Conmutator and derived subgroups $G'$.
127
+ * Abelianization $G/G'$
113
128
 
114
129
  **AUTOMORPHISMS:**
115
130
  * Class `Automorphism` and automorphism functions.
@@ -138,6 +153,7 @@ The GroupsMath team is currently working on theese ideas:
138
153
  * Representation theory.
139
154
  * and much more...
140
155
 
156
+
141
157
  ---
142
158
 
143
159
  ## Documentation
@@ -146,14 +162,6 @@ Detailed documentation is available in the [`docs`](https://github.com/MarioSult
146
162
 
147
163
  ---
148
164
 
149
- ## Project status
150
-
151
- GroupsMath is currently under active development.
152
-
153
- The project has successfully transitioned to an object-oriented interface centered around the `Group` class. The legacy function-based interface is being removed for future versions. The API should therefore be considered unstable until the `1.0.0` release, and breaking changes may occur between development versions.
154
-
155
- ---
156
-
157
165
  ## Contributing
158
166
 
159
167
  Contributions, suggestions, and bug reports are welcome. If you find a bug or have an idea for improving GroupsMath, please open an issue in the GitHub repository.
@@ -1,13 +1,24 @@
1
- # GroupsMath – v0.5.0
1
+ # GroupsMath – v0.6.0
2
+
3
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/groupsmath)](https://pypistats.org/packages/groupsmath)
4
+ [![PyPI Version](https://img.shields.io/pypi/v/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
5
+ [![Python Versions](https://img.shields.io/pypi/pyversions/groupsmath?color=2A646E)](https://pypi.org/project/groupsmath/)
6
+ ![Last Commit](https://img.shields.io/github/last-commit/MarioSultan/groupsmath?color=2A646E)
7
+ ![coverage](https://img.shields.io/badge/road%20to%20v1.0.0-85%25-yellowgreen?color=2A646E)
8
+ <!-- ![GitHub Stars](https://img.shields.io/github/stars/MarioSultan/groupsmath?style=social) -->
9
+
2
10
 
3
11
  ![GroupsMath Logo](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/logo.png)
4
12
 
5
13
 
6
14
  **GroupsMath** is a Python module for constructing, studying, and manipulating finite and infinite groups.
7
15
 
8
- The project aims to provide a simple and intuitive interface for working with finite groups and their algebraic properties.
16
+ The project aims to provide a **simple** and **intuitive** interface for working with groups and their algebraic properties.
17
+
18
+ ![Examples](https://raw.githubusercontent.com/MarioSultan/GroupsMath/main/imgs/examples.png)
19
+
20
+ > **⚠️ Notice:** Version v1.0.0 is nearing its official release.
9
21
 
10
- > **Note:** GroupsMath is currently under active development. Its API is still evolving and may change before version `1.0.0`.
11
22
 
12
23
  ---
13
24
 
@@ -29,7 +40,7 @@ or visit https://github.com/MarioSultan/GroupsMath and download all the files.
29
40
 
30
41
  ---
31
42
 
32
- ## Examples
43
+ ## Quick start
33
44
 
34
45
  ### A program in GroupsMath
35
46
  ```python
@@ -80,14 +91,18 @@ GroupsMath is designed to provide tools for working with finite (and infinite) g
80
91
  * Determination of the order of a group and its elements.
81
92
  * Operation with group elements (multiplication, inverse, powers, ...)
82
93
  * Computation of Cayley tables with `matplotlib.pyplot`.
83
- * Detection of algebraic properties such as cyclicity and commutativity.
94
+ * Detection of algebraic properties such as cyclicity, commutativity and solubility.
95
+ * Centralizers, conjugacy classes and conmutator.
84
96
  * Computation and exploration of other structural properties of finite groups.
85
97
  * Predefined group families in the library `groupsmath.precooked`, such as $C_n$, $S_n$, $A_n$, $D_n$, $V_4$, $Q_8$, ...
98
+ * Isomorphisms between groups.
86
99
 
87
100
  **SUBGROUPS:**
88
101
  * Study of subgroups (order, cosets, normal subgroups, quotients, ...).
89
102
  * Normal subgroups.
90
103
  * Quotient groups $Q=G/H$.
104
+ * Conmutator and derived subgroups $G'$.
105
+ * Abelianization $G/G'$
91
106
 
92
107
  **AUTOMORPHISMS:**
93
108
  * Class `Automorphism` and automorphism functions.
@@ -116,6 +131,7 @@ The GroupsMath team is currently working on theese ideas:
116
131
  * Representation theory.
117
132
  * and much more...
118
133
 
134
+
119
135
  ---
120
136
 
121
137
  ## Documentation
@@ -124,14 +140,6 @@ Detailed documentation is available in the [`docs`](https://github.com/MarioSult
124
140
 
125
141
  ---
126
142
 
127
- ## Project status
128
-
129
- GroupsMath is currently under active development.
130
-
131
- The project has successfully transitioned to an object-oriented interface centered around the `Group` class. The legacy function-based interface is being removed for future versions. The API should therefore be considered unstable until the `1.0.0` release, and breaking changes may occur between development versions.
132
-
133
- ---
134
-
135
143
  ## Contributing
136
144
 
137
145
  Contributions, suggestions, and bug reports are welcome. If you find a bug or have an idea for improving GroupsMath, please open an issue in the GitHub repository.
@@ -21,7 +21,7 @@ from math import gcd
21
21
 
22
22
  #################### DEFINITIONS ####################
23
23
 
24
- __version__ = "0.5.0"
24
+ __version__ = "0.6.0"
25
25
  __errorcolor__ = "\033[31m"
26
26
 
27
27
  tgl_color = "#2A646E"
@@ -50,7 +50,7 @@ def groupsmath_info():
50
50
  print("———————————————————————————————————————————————————————————————————————————")
51
51
 
52
52
 
53
- #################### GROUP CLASS ####################
53
+ #################### CLASSES ####################
54
54
 
55
55
  class Group(ABC):
56
56
  @classmethod
@@ -242,6 +242,95 @@ class ExplicitGroup(Group):
242
242
  if subgroup.group is not self:
243
243
  raise ValueError(__errorcolor__+"The subgroup does not belong to this group")
244
244
  return subgroup.quotient()
245
+
246
+ def centralizer(self, element):
247
+ if element not in self.elements:
248
+ raise ValueError(__errorcolor__ + f"Element '{element}' is not in group")
249
+
250
+ cent = [g for g in self.elements if self.function(g, element) == self.function(element, g)]
251
+ sub_grp = ExplicitGroup(cent, self.function, _skip_validation=True)
252
+ return ExplicitSubgroup(sub_grp, self)
253
+
254
+ def conjugacy_class(self, element):
255
+ if element not in self.elements:
256
+ raise ValueError(__errorcolor__ + f"Element '{element}' is not in group")
257
+
258
+ c_class = set()
259
+ for g in self.elements:
260
+ g_inv = self.inverse(g)
261
+ # g * element * g^-1
262
+ conj = self.function(self.function(g, element), g_inv)
263
+ c_class.add(conj)
264
+ return list(c_class)
265
+
266
+ def conjugacy_classes(self):
267
+ classes = []
268
+ visited = set()
269
+ for e in self.elements:
270
+ if e not in visited:
271
+ c = self.conjugacy_class(e)
272
+ classes.append(c)
273
+ visited.update(c)
274
+ return classes
275
+
276
+ def commutator(self, a, b):
277
+ if a not in self.elements or b not in self.elements:
278
+ raise ValueError(__errorcolor__ + "Elements must belong to group")
279
+ a_inv = self.inverse(a)
280
+ b_inv = self.inverse(b)
281
+ return self.function(self.function(self.function(a, b), a_inv), b_inv)
282
+
283
+ def commutator_subgroup(self):
284
+ generators = set()
285
+ for a in self.elements:
286
+ for b in self.elements:
287
+ generators.add(self.commutator(a, b))
288
+
289
+ # Clausura del conjunto de conmutadores
290
+ elements = list(generators)
291
+ changed = True
292
+ while changed:
293
+ changed = False
294
+ for x in list(elements):
295
+ for y in list(elements):
296
+ prod = self.function(x, y)
297
+ if prod not in elements:
298
+ elements.append(prod)
299
+ changed = True
300
+
301
+ sub_grp = ExplicitGroup(elements, self.function, _skip_validation=True)
302
+ return ExplicitSubgroup(sub_grp, self)
303
+
304
+ def derived_subgroup(self, n=1):
305
+ if n < 0:
306
+ raise ValueError(__errorcolor__ + "n must be a non-negative integer")
307
+ if n == 0:
308
+ return ExplicitSubgroup(self, self)
309
+
310
+ current = self.commutator_subgroup()
311
+ for _ in range(n - 1):
312
+ current = current.commutator_subgroup()
313
+ return current
314
+
315
+ def derived_series(self):
316
+ series = [ExplicitSubgroup(self, self)]
317
+ current = self.commutator_subgroup()
318
+ series.append(current)
319
+
320
+ while True:
321
+ next_sub = current.commutator_subgroup()
322
+ if len(next_sub) == len(current):
323
+ break
324
+ series.append(next_sub)
325
+ current = next_sub
326
+
327
+ return series
328
+
329
+ def abelianization(self):
330
+ return self.quotient(self.commutator_subgroup())
331
+
332
+ def is_solvable(self):
333
+ return len(self.derived_series()[-1]) == 1
245
334
 
246
335
  #–> AUTOMORPHISMS
247
336
 
@@ -254,6 +343,29 @@ class ExplicitGroup(Group):
254
343
  def automorphism_group(self): # REVISAR (Aunque seguramente se quede así)
255
344
  return self.toCayleyGroup().automorphism_group().toExplicitGroup()
256
345
 
346
+ #–> GENERATORS
347
+
348
+ def generators(self):
349
+ """Devuelve un conjunto de generadores que genera todo el grupo."""
350
+ cayley_grp = self.toCayleyGroup()
351
+ gen_indices = cayley_grp.generators()
352
+ return [self.elements[i] for i in gen_indices]
353
+
354
+ def generates(self, subset):
355
+ """Comprueba si un subconjunto de elementos genera el grupo."""
356
+ if not all(e in self.elements for e in subset):
357
+ raise ValueError(__errorcolor__ + "All elements in subset must belong to the group.")
358
+
359
+ cayley_grp = self.toCayleyGroup()
360
+ subset_indices = [self.elements.index(e) for e in subset]
361
+ sub_indices = _subgroup_generated_by(cayley_grp.cayley, subset_indices)
362
+ return len(sub_indices) == len(self)
363
+
364
+ #-> ISOMORPHISMS
365
+
366
+ def is_isomorphic_to(self, target):
367
+ return self.toCayleyGroup().is_isomorphic_to(target)
368
+
257
369
  class CayleyGroup(Group):
258
370
 
259
371
  def __init__(self, cayley, elements=None, _skip_validation=False):
@@ -497,6 +609,103 @@ class CayleyGroup(Group):
497
609
  raise ValueError(__errorcolor__+"The subgroup does not belong to this group")
498
610
  return subgroup.quotient()
499
611
 
612
+ def centralizer(self, element):
613
+ if element not in self.elements:
614
+ raise ValueError(__errorcolor__ + f"Element '{element}' is not in group")
615
+
616
+ a_idx = self._dict[element]
617
+ cent_indices = [g_idx for g_idx in range(self.order()) if self.cayley[g_idx][a_idx] == self.cayley[a_idx][g_idx]]
618
+
619
+ sub_names = [self.elements[i] for i in cent_indices]
620
+ sub_matrix = _reset_renaming(_subset(self.cayley, cent_indices))
621
+ sub_grp = CayleyGroup(sub_matrix, sub_names, _skip_validation=True)
622
+ return CayleySubgroup(sub_grp, self)
623
+
624
+ def conjugacy_class(self, element):
625
+ if element not in self.elements:
626
+ raise ValueError(__errorcolor__ + f"Element '{element}' is not in group")
627
+
628
+ a_idx = self._dict[element]
629
+ c_class_indices = set()
630
+ for g_idx in range(self.order()):
631
+ g_inv_idx = self.cayley[g_idx].index(self._dict[self.identity()])
632
+ conj_idx = self.cayley[self.cayley[g_idx][a_idx]][g_inv_idx]
633
+ c_class_indices.add(conj_idx)
634
+ return [self.elements[i] for i in c_class_indices]
635
+
636
+ def conjugacy_classes(self):
637
+ classes = []
638
+ visited = set()
639
+ for e in self.elements:
640
+ if e not in visited:
641
+ c = self.conjugacy_class(e)
642
+ classes.append(c)
643
+ visited.update(c)
644
+ return classes
645
+
646
+ def commutator(self, a, b):
647
+ return self.operation(self.operation(self.operation(a,b),self.inverse(a)),self.inverse(b))
648
+
649
+ def commutator_subgroup(self):
650
+ e_idx = self._dict[self.identity()]
651
+ gen_indices = set()
652
+ for a in range(self.order()):
653
+ for b in range(self.order()):
654
+ a_inv = self.cayley[a].index(e_idx)
655
+ b_inv = self.cayley[b].index(e_idx)
656
+ comm = self.cayley[self.cayley[self.cayley[a][b]][a_inv]][b_inv]
657
+ gen_indices.add(comm)
658
+
659
+ # Clausura
660
+ indices = list(gen_indices)
661
+ changed = True
662
+ while changed:
663
+ changed = False
664
+ for x in list(indices):
665
+ for y in list(indices):
666
+ prod = self.cayley[x][y]
667
+ if prod not in indices:
668
+ indices.append(prod)
669
+ changed = True
670
+
671
+ sub_names = [self.elements[i] for i in indices]
672
+ sub_matrix = _reset_renaming(_subset(self.cayley, indices))
673
+ sub_grp = CayleyGroup(sub_matrix, sub_names, _skip_validation=True)
674
+ return CayleySubgroup(sub_grp, self)
675
+
676
+ def derived_subgroup(self, n=1):
677
+ if n < 0:
678
+ raise ValueError(__errorcolor__ + "n must be a non-negative integer")
679
+ if n == 0:
680
+ total_grp = CayleyGroup(self.cayley, self.elements)
681
+ return CayleySubgroup(total_grp, self)
682
+
683
+ current = self.commutator_subgroup()
684
+ for _ in range(n - 1):
685
+ current = current.commutator_subgroup()
686
+ return current
687
+
688
+ def derived_series(self):
689
+ total_grp = CayleyGroup(self.cayley, self.elements)
690
+ series = [CayleySubgroup(total_grp, self)]
691
+ current = self.commutator_subgroup()
692
+ series.append(current)
693
+
694
+ while True:
695
+ next_sub = current.commutator_subgroup()
696
+ if len(next_sub) == len(current):
697
+ break
698
+ series.append(next_sub)
699
+ current = next_sub
700
+
701
+ return series
702
+
703
+ def abelianization(self):
704
+ return self.quotient(self.commutator_subgroup())
705
+
706
+ def is_solvable(self):
707
+ return len(self.derived_series()[-1]) == 1
708
+
500
709
  #–> AUTOMORPHISMS
501
710
 
502
711
  def is_automorphism(self, phi):
@@ -556,6 +765,133 @@ class CayleyGroup(Group):
556
765
  names_aut = [str(auts[i]) for i in range(n)]
557
766
  return CayleyGroup(cayley_aut, names_aut, _skip_validation=True)
558
767
 
768
+ #–> GENERATORS
769
+
770
+ def generators(self):
771
+ """Devuelve una lista con los elementos de un conjunto generador minimal."""
772
+ e_idx = self.identity()
773
+ current_subgroup = {e_idx}
774
+ generators_indices = []
775
+
776
+ while len(current_subgroup) < self.order():
777
+ # Buscar el elemento fuera del subgrupo actual que maximice la clausura
778
+ best_candidate = None
779
+ best_closure = current_subgroup
780
+
781
+ for candidate in range(self.order()):
782
+ if candidate not in current_subgroup:
783
+ test_gens = generators_indices + [candidate]
784
+ closure = set(_subgroup_generated_by(self.cayley, test_gens))
785
+
786
+ if len(closure) > len(best_closure):
787
+ best_closure = closure
788
+ best_candidate = candidate
789
+
790
+ # Si ya alcanzamos todo el grupo, terminamos temprano
791
+ if len(closure) == self.order():
792
+ generators_indices.append(candidate)
793
+ return [self.elements[i] for i in generators_indices]
794
+
795
+ generators_indices.append(best_candidate)
796
+ current_subgroup = best_closure
797
+
798
+ return [self.elements[i] for i in generators_indices]
799
+
800
+ def generates(self, subset):
801
+ """Comprueba si un subconjunto de elementos genera el grupo."""
802
+ if not all(e in self.elements for e in subset):
803
+ raise ValueError(__errorcolor__ + "All elements in subset must belong to the group.")
804
+
805
+ subset_indices = [self._dict[e] for e in subset]
806
+ sub_indices = _subgroup_generated_by(self.cayley, subset_indices)
807
+ return len(sub_indices) == self.order()
808
+
809
+ #-> ISOMORPHISMS
810
+
811
+ def is_isomorphic_to(self, target): #Revisar, pues es demasiado grande y algo puede salir mal
812
+ """Comprueba si el grupo actual es isomorfo al grupo 'target'."""
813
+ # Convertir a CayleyGroup si se pasa un ExplicitGroup
814
+ if hasattr(target, "toCayleyGroup"):
815
+ H = target.toCayleyGroup()
816
+ else:
817
+ H = target
818
+
819
+ G = self
820
+
821
+ # --- FASE 1: Filtros de Invariantes Algebraicos ---
822
+ if G.order() != H.order():
823
+ return False
824
+
825
+ if G.is_abelian() != H.is_abelian():
826
+ return False
827
+
828
+ if G.order_distribution() != H.order_distribution():
829
+ return False
830
+
831
+ if len(G.center()) != len(H.center()):
832
+ return False
833
+
834
+ # --- FASE 2: Búsqueda de Isomorfismo vía Generadores ---
835
+ n = G.order()
836
+
837
+ # 1. Obtener generadores del grupo G (por índices)
838
+ e_idx_G = self._dict[G.identity()]
839
+ gens_G = G.generators()
840
+ gens_G_idx = [G._dict[g] for g in gens_G]
841
+
842
+ # 2. Candidatos en H para cada generador de G (deben tener el mismo orden)
843
+ orders_G = G.element_orders()
844
+ orders_H = H.element_orders()
845
+
846
+ candidates_per_gen = []
847
+ for g_idx in gens_G_idx:
848
+ g_order = orders_G[g_idx]
849
+ candidates = [h_idx for h_idx, o in enumerate(orders_H) if o == g_order]
850
+ candidates_per_gen.append(candidates)
851
+
852
+ # 3. Probar asignaciones de generadores
853
+ for tuple_h_indices in product(*candidates_per_gen):
854
+ # Mapear generadores de G -> H
855
+ mapping = {e_idx_G: H._dict[H.identity()]}
856
+ queue = [e_idx_G]
857
+
858
+ # Extender el mapeo a todo el grupo a través de la multiplicación por generadores
859
+ valid_extension = True
860
+
861
+ while queue and valid_extension:
862
+ curr = queue.pop(0)
863
+ for i, g_idx in enumerate(gens_G_idx):
864
+ h_gen = tuple_h_indices[i]
865
+
866
+ # Multiplicación curr * g en G
867
+ next_g = G.cayley[curr][g_idx]
868
+ expected_h = H.cayley[mapping[curr]][h_gen]
869
+
870
+ if next_g in mapping:
871
+ if mapping[next_g] != expected_h:
872
+ valid_extension = False
873
+ break
874
+ else:
875
+ mapping[next_g] = expected_h
876
+ queue.append(next_g)
877
+
878
+ # Comprobar si el mapeo generado es una biyección inyectiva sobre H y preserva toda la Cayley
879
+ if valid_extension and len(mapping) == n and len(set(mapping.values())) == n:
880
+ # Validación final de la preservación de la operación para todo (a, b)
881
+ is_iso = True
882
+ for a in range(n):
883
+ for b in range(n):
884
+ if mapping[G.cayley[a][b]] != H.cayley[mapping[a]][mapping[b]]:
885
+ is_iso = False
886
+ break
887
+ if not is_iso:
888
+ break
889
+
890
+ if is_iso:
891
+ return True
892
+
893
+ return False
894
+
559
895
  class Subgroup(ABC):
560
896
  pass
561
897
 
@@ -1126,6 +1462,30 @@ def _operate_cosets(G,C,A,B):
1126
1462
  break
1127
1463
  return r
1128
1464
 
1465
+ def _subgroup_generated_by(cayley, generators_indices):
1466
+
1467
+ generated = set(generators_indices)
1468
+ queue = list(generators_indices)
1469
+
1470
+ while queue:
1471
+
1472
+ current = queue.pop(0)
1473
+
1474
+ for g in generators_indices:
1475
+
1476
+ prod1 = cayley[current][g]
1477
+ prod2 = cayley[g][current]
1478
+
1479
+ if prod1 not in generated:
1480
+ generated.add(prod1)
1481
+ queue.append(prod1)
1482
+
1483
+ if prod2 not in generated:
1484
+ generated.add(prod2)
1485
+ queue.append(prod2)
1486
+
1487
+ return sorted(list(generated))
1488
+
1129
1489
  def _order_preserving_permutations(orders):
1130
1490
 
1131
1491
  classes = {}
@@ -1168,12 +1528,17 @@ def direct_product(A:CayleyGroup,B:CayleyGroup):
1168
1528
  return CayleyGroup(G,names,_skip_validation=True)
1169
1529
 
1170
1530
  def direct_power(G:CayleyGroup,n):
1171
- if n<2:
1172
- raise ValueError("n must be at least 2")
1173
- H = G
1174
- for i in range(n-1):
1175
- H = direct_product(H,G)
1176
- return H
1531
+ if n==2:
1532
+ return CayleyGroup([[0]],"e")
1533
+ elif n==1:
1534
+ return G
1535
+ elif n>2:
1536
+ H = G
1537
+ for i in range(n-1):
1538
+ H = direct_product(H,G)
1539
+ return H
1540
+ else:
1541
+ raise ValueError(__errorcolor__+"n must be a possitive integer.")
1177
1542
 
1178
1543
  def semidirect_product(A: CayleyGroup, B: CayleyGroup, f: AutomorphismFunction):
1179
1544
  G = []
@@ -1201,6 +1566,15 @@ def semidirect_product(A: CayleyGroup, B: CayleyGroup, f: AutomorphismFunction):
1201
1566
  return CayleyGroup(G, names, _skip_validation=True)
1202
1567
 
1203
1568
 
1569
+ #################### ISOMORPHISMS ####################
1570
+
1571
+ def are_isomorphic(G: Group, H: Group) -> bool:
1572
+ """Devuelve True si los grupos G y H son isomorfos, False en caso contrario."""
1573
+ if not isinstance(G, Group) or not isinstance(H, Group):
1574
+ raise TypeError(__errorcolor__ + "Both arguments must be instances of Group")
1575
+ return G.is_isomorphic_to(H)
1576
+
1577
+
1204
1578
  #################### GENERATORS ####################
1205
1579
 
1206
1580
  def cyclic_group(n):
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GroupsMath" # Nombre en PyPI (ej: mi-paquete)
7
- version = "0.5.0"
7
+ version = "0.6.0"
8
8
  description = "The educational Python library for Group Theory"
9
9
  readme = "README.md" # Esta será la documentación visible en la portada de PyPI
10
10
  requires-python = ">=3.8"
File without changes
File without changes