Initial import: grid-bot — grid trading bot for BTC-USDT on Cifra Markets
This commit is contained in:
@@ -0,0 +1,710 @@
|
||||
from sympy.ntheory.primetest import isprime
|
||||
from sympy.combinatorics.perm_groups import PermutationGroup
|
||||
from sympy.printing.defaults import DefaultPrinting
|
||||
from sympy.combinatorics.free_groups import free_group
|
||||
|
||||
|
||||
class PolycyclicGroup(DefaultPrinting):
|
||||
|
||||
is_group = True
|
||||
is_solvable = True
|
||||
|
||||
def __init__(self, pc_sequence, pc_series, relative_order, collector=None):
|
||||
"""
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
pc_sequence : list
|
||||
A sequence of elements whose classes generate the cyclic factor
|
||||
groups of pc_series.
|
||||
pc_series : list
|
||||
A subnormal sequence of subgroups where each factor group is cyclic.
|
||||
relative_order : list
|
||||
The orders of factor groups of pc_series.
|
||||
collector : Collector
|
||||
By default, it is None. Collector class provides the
|
||||
polycyclic presentation with various other functionalities.
|
||||
|
||||
"""
|
||||
self.pcgs = pc_sequence
|
||||
self.pc_series = pc_series
|
||||
self.relative_order = relative_order
|
||||
self.collector = Collector(self.pcgs, pc_series, relative_order) if not collector else collector
|
||||
|
||||
def is_prime_order(self):
|
||||
return all(isprime(order) for order in self.relative_order)
|
||||
|
||||
def length(self):
|
||||
return len(self.pcgs)
|
||||
|
||||
|
||||
class Collector(DefaultPrinting):
|
||||
|
||||
"""
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Holt, D., Eick, B., O'Brien, E.
|
||||
"Handbook of Computational Group Theory"
|
||||
Section 8.1.3
|
||||
"""
|
||||
|
||||
def __init__(self, pcgs, pc_series, relative_order, free_group_=None, pc_presentation=None):
|
||||
"""
|
||||
|
||||
Most of the parameters for the Collector class are the same as for PolycyclicGroup.
|
||||
Others are described below.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
free_group_ : tuple
|
||||
free_group_ provides the mapping of polycyclic generating
|
||||
sequence with the free group elements.
|
||||
pc_presentation : dict
|
||||
Provides the presentation of polycyclic groups with the
|
||||
help of power and conjugate relators.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
PolycyclicGroup
|
||||
|
||||
"""
|
||||
self.pcgs = pcgs
|
||||
self.pc_series = pc_series
|
||||
self.relative_order = relative_order
|
||||
self.free_group = free_group('x:{}'.format(len(pcgs)))[0] if not free_group_ else free_group_
|
||||
self.index = {s: i for i, s in enumerate(self.free_group.symbols)}
|
||||
self.pc_presentation = self.pc_relators()
|
||||
|
||||
def minimal_uncollected_subword(self, word):
|
||||
r"""
|
||||
Returns the minimal uncollected subwords.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
A word ``v`` defined on generators in ``X`` is a minimal
|
||||
uncollected subword of the word ``w`` if ``v`` is a subword
|
||||
of ``w`` and it has one of the following form
|
||||
|
||||
* `v = {x_{i+1}}^{a_j}x_i`
|
||||
|
||||
* `v = {x_{i+1}}^{a_j}{x_i}^{-1}`
|
||||
|
||||
* `v = {x_i}^{a_j}`
|
||||
|
||||
for `a_j` not in `\{1, \ldots, s-1\}`. Where, ``s`` is the power
|
||||
exponent of the corresponding generator.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics import free_group
|
||||
>>> G = SymmetricGroup(4)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> F, x1, x2 = free_group("x1, x2")
|
||||
>>> word = x2**2*x1**7
|
||||
>>> collector.minimal_uncollected_subword(word)
|
||||
((x2, 2),)
|
||||
|
||||
"""
|
||||
# To handle the case word = <identity>
|
||||
if not word:
|
||||
return None
|
||||
|
||||
array = word.array_form
|
||||
re = self.relative_order
|
||||
index = self.index
|
||||
|
||||
for i in range(len(array)):
|
||||
s1, e1 = array[i]
|
||||
|
||||
if re[index[s1]] and (e1 < 0 or e1 > re[index[s1]]-1):
|
||||
return ((s1, e1), )
|
||||
|
||||
for i in range(len(array)-1):
|
||||
s1, e1 = array[i]
|
||||
s2, e2 = array[i+1]
|
||||
|
||||
if index[s1] > index[s2]:
|
||||
e = 1 if e2 > 0 else -1
|
||||
return ((s1, e1), (s2, e))
|
||||
|
||||
return None
|
||||
|
||||
def relations(self):
|
||||
"""
|
||||
Separates the given relators of pc presentation in power and
|
||||
conjugate relations.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(power_rel, conj_rel)
|
||||
Separates pc presentation into power and conjugate relations.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> G = SymmetricGroup(3)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> power_rel, conj_rel = collector.relations()
|
||||
>>> power_rel
|
||||
{x0**2: (), x1**3: ()}
|
||||
>>> conj_rel
|
||||
{x0**-1*x1*x0: x1**2}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
pc_relators
|
||||
|
||||
"""
|
||||
power_relators = {}
|
||||
conjugate_relators = {}
|
||||
for key, value in self.pc_presentation.items():
|
||||
if len(key.array_form) == 1:
|
||||
power_relators[key] = value
|
||||
else:
|
||||
conjugate_relators[key] = value
|
||||
return power_relators, conjugate_relators
|
||||
|
||||
def subword_index(self, word, w):
|
||||
"""
|
||||
Returns the start and ending index of a given
|
||||
subword in a word.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
word : FreeGroupElement
|
||||
word defined on free group elements for a
|
||||
polycyclic group.
|
||||
w : FreeGroupElement
|
||||
subword of a given word, whose starting and
|
||||
ending index to be computed.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(i, j)
|
||||
A tuple containing starting and ending index of ``w``
|
||||
in the given word. If not exists, (-1,-1) is returned.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics import free_group
|
||||
>>> G = SymmetricGroup(4)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> F, x1, x2 = free_group("x1, x2")
|
||||
>>> word = x2**2*x1**7
|
||||
>>> w = x2**2*x1
|
||||
>>> collector.subword_index(word, w)
|
||||
(0, 3)
|
||||
>>> w = x1**7
|
||||
>>> collector.subword_index(word, w)
|
||||
(2, 9)
|
||||
>>> w = x1**8
|
||||
>>> collector.subword_index(word, w)
|
||||
(-1, -1)
|
||||
|
||||
"""
|
||||
low = -1
|
||||
high = -1
|
||||
for i in range(len(word)-len(w)+1):
|
||||
if word.subword(i, i+len(w)) == w:
|
||||
low = i
|
||||
high = i+len(w)
|
||||
break
|
||||
return low, high
|
||||
|
||||
def map_relation(self, w):
|
||||
"""
|
||||
Return a conjugate relation.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a word formed by two free group elements, the
|
||||
corresponding conjugate relation with those free
|
||||
group elements is formed and mapped with the collected
|
||||
word in the polycyclic presentation.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics import free_group
|
||||
>>> G = SymmetricGroup(3)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> F, x0, x1 = free_group("x0, x1")
|
||||
>>> w = x1*x0
|
||||
>>> collector.map_relation(w)
|
||||
x1**2
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
pc_presentation
|
||||
|
||||
"""
|
||||
array = w.array_form
|
||||
s1 = array[0][0]
|
||||
s2 = array[1][0]
|
||||
key = ((s2, -1), (s1, 1), (s2, 1))
|
||||
key = self.free_group.dtype(key)
|
||||
return self.pc_presentation[key]
|
||||
|
||||
|
||||
def collected_word(self, word):
|
||||
r"""
|
||||
Return the collected form of a word.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
A word ``w`` is called collected, if `w = {x_{i_1}}^{a_1} * \ldots *
|
||||
{x_{i_r}}^{a_r}` with `i_1 < i_2< \ldots < i_r` and `a_j` is in
|
||||
`\{1, \ldots, {s_j}-1\}`.
|
||||
|
||||
Otherwise w is uncollected.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
word : FreeGroupElement
|
||||
An uncollected word.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
word
|
||||
A collected word of form `w = {x_{i_1}}^{a_1}, \ldots,
|
||||
{x_{i_r}}^{a_r}` with `i_1, i_2, \ldots, i_r` and `a_j \in
|
||||
\{1, \ldots, {s_j}-1\}`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics.perm_groups import PermutationGroup
|
||||
>>> from sympy.combinatorics import free_group
|
||||
>>> G = SymmetricGroup(4)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> F, x0, x1, x2, x3 = free_group("x0, x1, x2, x3")
|
||||
>>> word = x3*x2*x1*x0
|
||||
>>> collected_word = collector.collected_word(word)
|
||||
>>> free_to_perm = {}
|
||||
>>> free_group = collector.free_group
|
||||
>>> for sym, gen in zip(free_group.symbols, collector.pcgs):
|
||||
... free_to_perm[sym] = gen
|
||||
>>> G1 = PermutationGroup()
|
||||
>>> for w in word:
|
||||
... sym = w[0]
|
||||
... perm = free_to_perm[sym]
|
||||
... G1 = PermutationGroup([perm] + G1.generators)
|
||||
>>> G2 = PermutationGroup()
|
||||
>>> for w in collected_word:
|
||||
... sym = w[0]
|
||||
... perm = free_to_perm[sym]
|
||||
... G2 = PermutationGroup([perm] + G2.generators)
|
||||
|
||||
The two are not identical, but they are equivalent:
|
||||
|
||||
>>> G1.equals(G2), G1 == G2
|
||||
(True, False)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
minimal_uncollected_subword
|
||||
|
||||
"""
|
||||
free_group = self.free_group
|
||||
while True:
|
||||
w = self.minimal_uncollected_subword(word)
|
||||
if not w:
|
||||
break
|
||||
|
||||
low, high = self.subword_index(word, free_group.dtype(w))
|
||||
if low == -1:
|
||||
continue
|
||||
|
||||
s1, e1 = w[0]
|
||||
if len(w) == 1:
|
||||
re = self.relative_order[self.index[s1]]
|
||||
q = e1 // re
|
||||
r = e1-q*re
|
||||
|
||||
key = ((w[0][0], re), )
|
||||
key = free_group.dtype(key)
|
||||
if self.pc_presentation[key]:
|
||||
presentation = self.pc_presentation[key].array_form
|
||||
sym, exp = presentation[0]
|
||||
word_ = ((w[0][0], r), (sym, q*exp))
|
||||
word_ = free_group.dtype(word_)
|
||||
else:
|
||||
if r != 0:
|
||||
word_ = ((w[0][0], r), )
|
||||
word_ = free_group.dtype(word_)
|
||||
else:
|
||||
word_ = None
|
||||
word = word.eliminate_word(free_group.dtype(w), word_)
|
||||
|
||||
if len(w) == 2 and w[1][1] > 0:
|
||||
s2, e2 = w[1]
|
||||
s2 = ((s2, 1), )
|
||||
s2 = free_group.dtype(s2)
|
||||
word_ = self.map_relation(free_group.dtype(w))
|
||||
word_ = s2*word_**e1
|
||||
word_ = free_group.dtype(word_)
|
||||
word = word.substituted_word(low, high, word_)
|
||||
|
||||
elif len(w) == 2 and w[1][1] < 0:
|
||||
s2, e2 = w[1]
|
||||
s2 = ((s2, 1), )
|
||||
s2 = free_group.dtype(s2)
|
||||
word_ = self.map_relation(free_group.dtype(w))
|
||||
word_ = s2**-1*word_**e1
|
||||
word_ = free_group.dtype(word_)
|
||||
word = word.substituted_word(low, high, word_)
|
||||
|
||||
return word
|
||||
|
||||
|
||||
def pc_relators(self):
|
||||
r"""
|
||||
Return the polycyclic presentation.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
There are two types of relations used in polycyclic
|
||||
presentation.
|
||||
|
||||
* Power relations : Power relators are of the form `x_i^{re_i}`,
|
||||
where `i \in \{0, \ldots, \mathrm{len(pcgs)}\}`, ``x`` represents polycyclic
|
||||
generator and ``re`` is the corresponding relative order.
|
||||
|
||||
* Conjugate relations : Conjugate relators are of the form `x_j^-1x_ix_j`,
|
||||
where `j < i \in \{0, \ldots, \mathrm{len(pcgs)}\}`.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
A dictionary with power and conjugate relations as key and
|
||||
their collected form as corresponding values.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Identity Permutation is mapped with empty ``()``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics.permutations import Permutation
|
||||
>>> S = SymmetricGroup(49).sylow_subgroup(7)
|
||||
>>> der = S.derived_series()
|
||||
>>> G = der[len(der)-2]
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> pcgs = PcGroup.pcgs
|
||||
>>> len(pcgs)
|
||||
6
|
||||
>>> free_group = collector.free_group
|
||||
>>> pc_resentation = collector.pc_presentation
|
||||
>>> free_to_perm = {}
|
||||
>>> for s, g in zip(free_group.symbols, pcgs):
|
||||
... free_to_perm[s] = g
|
||||
|
||||
>>> for k, v in pc_resentation.items():
|
||||
... k_array = k.array_form
|
||||
... if v != ():
|
||||
... v_array = v.array_form
|
||||
... lhs = Permutation()
|
||||
... for gen in k_array:
|
||||
... s = gen[0]
|
||||
... e = gen[1]
|
||||
... lhs = lhs*free_to_perm[s]**e
|
||||
... if v == ():
|
||||
... assert lhs.is_identity
|
||||
... continue
|
||||
... rhs = Permutation()
|
||||
... for gen in v_array:
|
||||
... s = gen[0]
|
||||
... e = gen[1]
|
||||
... rhs = rhs*free_to_perm[s]**e
|
||||
... assert lhs == rhs
|
||||
|
||||
"""
|
||||
free_group = self.free_group
|
||||
rel_order = self.relative_order
|
||||
pc_relators = {}
|
||||
perm_to_free = {}
|
||||
pcgs = self.pcgs
|
||||
|
||||
for gen, s in zip(pcgs, free_group.generators):
|
||||
perm_to_free[gen**-1] = s**-1
|
||||
perm_to_free[gen] = s
|
||||
|
||||
pcgs = pcgs[::-1]
|
||||
series = self.pc_series[::-1]
|
||||
rel_order = rel_order[::-1]
|
||||
collected_gens = []
|
||||
|
||||
for i, gen in enumerate(pcgs):
|
||||
re = rel_order[i]
|
||||
relation = perm_to_free[gen]**re
|
||||
G = series[i]
|
||||
|
||||
l = G.generator_product(gen**re, original = True)
|
||||
l.reverse()
|
||||
|
||||
word = free_group.identity
|
||||
for g in l:
|
||||
word = word*perm_to_free[g]
|
||||
|
||||
word = self.collected_word(word)
|
||||
pc_relators[relation] = word if word else ()
|
||||
self.pc_presentation = pc_relators
|
||||
|
||||
collected_gens.append(gen)
|
||||
if len(collected_gens) > 1:
|
||||
conj = collected_gens[len(collected_gens)-1]
|
||||
conjugator = perm_to_free[conj]
|
||||
|
||||
for j in range(len(collected_gens)-1):
|
||||
conjugated = perm_to_free[collected_gens[j]]
|
||||
|
||||
relation = conjugator**-1*conjugated*conjugator
|
||||
gens = conj**-1*collected_gens[j]*conj
|
||||
|
||||
l = G.generator_product(gens, original = True)
|
||||
l.reverse()
|
||||
word = free_group.identity
|
||||
for g in l:
|
||||
word = word*perm_to_free[g]
|
||||
|
||||
word = self.collected_word(word)
|
||||
pc_relators[relation] = word if word else ()
|
||||
self.pc_presentation = pc_relators
|
||||
|
||||
return pc_relators
|
||||
|
||||
def exponent_vector(self, element):
|
||||
r"""
|
||||
Return the exponent vector of length equal to the
|
||||
length of polycyclic generating sequence.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For a given generator/element ``g`` of the polycyclic group,
|
||||
it can be represented as `g = {x_1}^{e_1}, \ldots, {x_n}^{e_n}`,
|
||||
where `x_i` represents polycyclic generators and ``n`` is
|
||||
the number of generators in the free_group equal to the length
|
||||
of pcgs.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
element : Permutation
|
||||
Generator of a polycyclic group.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> from sympy.combinatorics.permutations import Permutation
|
||||
>>> G = SymmetricGroup(4)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> pcgs = PcGroup.pcgs
|
||||
>>> collector.exponent_vector(G[0])
|
||||
[1, 0, 0, 0]
|
||||
>>> exp = collector.exponent_vector(G[1])
|
||||
>>> g = Permutation()
|
||||
>>> for i in range(len(exp)):
|
||||
... g = g*pcgs[i]**exp[i] if exp[i] else g
|
||||
>>> assert g == G[1]
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Holt, D., Eick, B., O'Brien, E.
|
||||
"Handbook of Computational Group Theory"
|
||||
Section 8.1.1, Definition 8.4
|
||||
|
||||
"""
|
||||
free_group = self.free_group
|
||||
G = PermutationGroup()
|
||||
for g in self.pcgs:
|
||||
G = PermutationGroup([g] + G.generators)
|
||||
gens = G.generator_product(element, original = True)
|
||||
gens.reverse()
|
||||
|
||||
perm_to_free = {}
|
||||
for sym, g in zip(free_group.generators, self.pcgs):
|
||||
perm_to_free[g**-1] = sym**-1
|
||||
perm_to_free[g] = sym
|
||||
w = free_group.identity
|
||||
for g in gens:
|
||||
w = w*perm_to_free[g]
|
||||
|
||||
word = self.collected_word(w)
|
||||
|
||||
index = self.index
|
||||
exp_vector = [0]*len(free_group)
|
||||
word = word.array_form
|
||||
for t in word:
|
||||
exp_vector[index[t[0]]] = t[1]
|
||||
return exp_vector
|
||||
|
||||
def depth(self, element):
|
||||
r"""
|
||||
Return the depth of a given element.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The depth of a given element ``g`` is defined by
|
||||
`\mathrm{dep}[g] = i` if `e_1 = e_2 = \ldots = e_{i-1} = 0`
|
||||
and `e_i != 0`, where ``e`` represents the exponent-vector.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> G = SymmetricGroup(3)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> collector.depth(G[0])
|
||||
2
|
||||
>>> collector.depth(G[1])
|
||||
1
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Holt, D., Eick, B., O'Brien, E.
|
||||
"Handbook of Computational Group Theory"
|
||||
Section 8.1.1, Definition 8.5
|
||||
|
||||
"""
|
||||
exp_vector = self.exponent_vector(element)
|
||||
return next((i+1 for i, x in enumerate(exp_vector) if x), len(self.pcgs)+1)
|
||||
|
||||
def leading_exponent(self, element):
|
||||
r"""
|
||||
Return the leading non-zero exponent.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The leading exponent for a given element `g` is defined
|
||||
by `\mathrm{leading\_exponent}[g]` `= e_i`, if `\mathrm{depth}[g] = i`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> G = SymmetricGroup(3)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> collector.leading_exponent(G[1])
|
||||
1
|
||||
|
||||
"""
|
||||
exp_vector = self.exponent_vector(element)
|
||||
depth = self.depth(element)
|
||||
if depth != len(self.pcgs)+1:
|
||||
return exp_vector[depth-1]
|
||||
return None
|
||||
|
||||
def _sift(self, z, g):
|
||||
h = g
|
||||
d = self.depth(h)
|
||||
while d < len(self.pcgs) and z[d-1] != 1:
|
||||
k = z[d-1]
|
||||
e = self.leading_exponent(h)*(self.leading_exponent(k))**-1
|
||||
e = e % self.relative_order[d-1]
|
||||
h = k**-e*h
|
||||
d = self.depth(h)
|
||||
return h
|
||||
|
||||
def induced_pcgs(self, gens):
|
||||
"""
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
gens : list
|
||||
A list of generators on which polycyclic subgroup
|
||||
is to be defined.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.named_groups import SymmetricGroup
|
||||
>>> S = SymmetricGroup(8)
|
||||
>>> G = S.sylow_subgroup(2)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> gens = [G[0], G[1]]
|
||||
>>> ipcgs = collector.induced_pcgs(gens)
|
||||
>>> [gen.order() for gen in ipcgs]
|
||||
[2, 2, 2]
|
||||
>>> G = S.sylow_subgroup(3)
|
||||
>>> PcGroup = G.polycyclic_group()
|
||||
>>> collector = PcGroup.collector
|
||||
>>> gens = [G[0], G[1]]
|
||||
>>> ipcgs = collector.induced_pcgs(gens)
|
||||
>>> [gen.order() for gen in ipcgs]
|
||||
[3]
|
||||
|
||||
"""
|
||||
z = [1]*len(self.pcgs)
|
||||
G = gens
|
||||
while G:
|
||||
g = G.pop(0)
|
||||
h = self._sift(z, g)
|
||||
d = self.depth(h)
|
||||
if d < len(self.pcgs):
|
||||
for gen in z:
|
||||
if gen != 1:
|
||||
G.append(h**-1*gen**-1*h*gen)
|
||||
z[d-1] = h
|
||||
z = [gen for gen in z if gen != 1]
|
||||
return z
|
||||
|
||||
def constructive_membership_test(self, ipcgs, g):
|
||||
"""
|
||||
Return the exponent vector for induced pcgs.
|
||||
"""
|
||||
e = [0]*len(ipcgs)
|
||||
h = g
|
||||
d = self.depth(h)
|
||||
for i, gen in enumerate(ipcgs):
|
||||
while self.depth(gen) == d:
|
||||
f = self.leading_exponent(h)*self.leading_exponent(gen)
|
||||
f = f % self.relative_order[d-1]
|
||||
h = gen**(-f)*h
|
||||
e[i] = f
|
||||
d = self.depth(h)
|
||||
if h == 1:
|
||||
return e
|
||||
return False
|
||||
Reference in New Issue
Block a user