Определить, образует ли (*,G) ассоциативную группу в теории групп

Допустим, у меня есть группа G={a,b,e}, где a, b произвольные элементы, а e обозначает нейтральный элемент. Я придумал определенную таблицу Кейли и хочу проверить, правильно ли я сделал, проверив ассоциативность.

Это означает, что я хочу проверить для произвольных x,y,z в G, что x(yz)=(xy)z, потому что вручную я должен был бы проверить 3*3*3 = 27 случаев, что является просто орехами.

Я не слишком далеко продвинулся в своем кодировании, и я был бы благодарен за некоторые подсказки или изящные способы решения этой проблемы. Я новичок в Python, но у меня есть общее представление о циклах и функциях.

Моя идея программы:

Я определяю функцию, скажем, группу, которая принимает в качестве входных данных строку. Я добавляю строку с помощью функции.extend(string) в определенный список, который позволяет мне анализировать заданные входные данные один за другим.

С помощью оператора if можно сказать:

if checklist[0] == "a" and checklist[1] == "b":
    checklist.pop[0]
    checklist[0] = "e"

Я мог бы сначала удалить первую запись в списке, а затем заменить ее на желаемое новое значение. Я продолжал в том же духе, добавляя все больше и больше операторов if, и в конце рекурсивно вызывал мою функцию снова, и она заканчивалась бы, если бы длина моего контрольного списка была равна 1.

Однако это не очень элегантный код, который также сталкивается с проблемами в особых случаях. Поэтому я считаю, что мои усилия были напрасны, и я должен полагать, что есть гораздо более простое и более элегантное решение этой проблемы. Я надеюсь, что вы можете помочь мне направить меня в правильном направлении, чтобы найти его.


Пример кода (не полный, но концептуальный):

checklist = []

def group(abc):
    if len(checklist) == 1:
        return checklist
    else:
        checklist.extend(abc)
        if (checklist[0] == "a" and checklist[1] == "a"):
            checklist.pop(0)
            checklist[0] = "b"
        if (checklist[0] == "a" and checklist[1] == "b"):
            checklist.pop(0)
            checklist[0] = "e"
        if (checklist[0] == "a" and checklist[1] == "e"):
            checklist.pop(0)
            checklist[0] = "a"
        if (checklist[0] == "b" and checklist[1] == "a"):
            checklist.pop(0)
            checklist[0] == "e"
        if (checklist[0] == "b" and checklist[1] == "b"):
            checklist.pop(0)
            checklist[0] = "a"
        if (checklist[0] == "b" and checklist[1] == "e"):
            checklist.pop(0)
            checklist[0] = "b"
        if (checklist[0] == "e" and checklist[1] == "a"):
            checklist.pop(0)
            checklist[0] = "a"
        if (checklist[0] == "e" and checklist[1] == "b"):
            checklist.pop(0)
            checklist[0] = "b"
        if (checklist[0] == "e" and checklist[1] == "e"):
            checklist.pop(0)
            checklist[0] = "e"
        group(checklist)
        return checklist

2 ответа

Решение

Я бы просто использовал itertools.product генерировать каждую тройку элементов x, y, z вашей группы G и проверьте, что тройка ассоциативна.

Вы можете определить функцию, которая проверяет, является ли ваша групповая операция с определенной тройкой ассоциативной, и затем по очереди проверять каждую возможную тройку в группе. Если "associativity fails..." печатается, то G не является ассоциативным в вашей групповой операции.

import itertools

G = [0, 1, 2, 3, 4, 5] # or whatever your group might be

def is_associative(x, y, z):
    if (x*y)*z == x*(y*z):
        return True
    return False

xyz = itertools.product(G, repeat=3)

for three in xyz:
    if not is_associative(*three):
         print("associativity fails for %s, %s, %s") % three

Очевидно, что в определении is_associative, вы хотите заменить * с какой бы ни была ваша групповая операция.

То, что вы хотите, выглядит так:

def is_associative(m, G):
    return sum( [m(m(a,b),c)!=m(a,m(b,c)) for a in G for b in G for c in G])==0

где вы кормите его функцией m и списком G, где m:(G,G)->G

Где это может пойти плохо с произвольным m и G находится в (не) равенстве теста.

Давайте посмотрим, сможем ли мы сделать эту работу с (i,j,k) векторами и перекрестными произведениями в R^ 3

import numpy

def is_associative(m, equals, G):
    # count the unassociative triplets, return true if count is zero
    return sum( [\
                     not equals(m(m(a,b),c), m(a,m(b,c)) ) \
                     for a in G for b in G for c in G\
                 ])==0


# classic non-associative example in R^3

# G is 0 vector and unit vectors
G = [ [0,0,0], [1,0,0], [0,1,0], [0,0,1] ]

# m is cross product 
def m(a,b):
    return numpy.cross(a,b)

def vector_equals(a,b):
    return (a[0]==b[0]) and (a[1]==b[1]) and (a[2]==b[2])

for a in G:
    print a

print "Associative: "+str(is_associative(m, vector_equals, G))

Выходные данные: [0, 0, 0] [1, 0, 0] [0, 1, 0] [0, 0, 1] Ассоциативно: False

Возможно, вы захотите узнать, почему конечная группа не ассоциативна, поэтому мы можем немного изменить ситуацию, чтобы выполнить это следующим образом:

Во-первых, мы определим функцию test_associative, которая возвращает не только истину / ложь, но и триплеты, которые вызывают ее ложь. Затем мы позвоним и распакуем результаты.

импорт NumPy

def test_associative(m, equals, G):
    # find the unassociative triplets
    # return (true,[]) if count is zero
    # return (false, array_of_unassociative_triplets)
    unassociative_triplets = [ (a,b,c)\
                     for a in G for b in G for c in G\
                     if not equals(m(m(a,b),c), m(a,m(b,c)) ) \
                 ]
    return (len(unassociative_triplets)==0, unassociative_triplets)


# classic non-associative example in R^3

# G is 0 vector and unit vectors
G = [ [0,0,0], [1,0,0], [0,1,0], [0,0,1] ]

# m is cross product 
def m(a,b):
    return numpy.cross(a,b)

def vector_equals(a,b):
    return (a[0]==b[0]) and (a[1]==b[1]) and (a[2]==b[2])

print "Elements of G:"

for a in G:
    print a

print "m() is the vector cross product x"

(is_associative, whynot) = test_associative(m, vector_equals, G)

print "Associative: "+str(is_associative)

if not is_associative:
    print "Non-associative triplets:"
    for triplet in whynot:
        print str(triplet)+\
            " (a*b)*c : "+str(m(m(triplet[0],triplet[1]), triplet[2]))+\
            " a*(b*c) : "+str(m(triplet[0],m(triplet[1], triplet[2])))

Выход:

Elements of G:
[0, 0, 0]
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
m() is the vector cross product x
Associative: False
Non-associative triplets:
([1, 0, 0], [1, 0, 0], [0, 1, 0]) (a*b)*c : [0 0 0] a*(b*c) : [ 0 -1  0]
([1, 0, 0], [1, 0, 0], [0, 0, 1]) (a*b)*c : [0 0 0] a*(b*c) : [ 0  0 -1]
([1, 0, 0], [0, 1, 0], [0, 1, 0]) (a*b)*c : [-1  0  0] a*(b*c) : [0 0 0]
([1, 0, 0], [0, 0, 1], [0, 0, 1]) (a*b)*c : [-1  0  0] a*(b*c) : [0 0 0]
([0, 1, 0], [1, 0, 0], [1, 0, 0]) (a*b)*c : [ 0 -1  0] a*(b*c) : [0 0 0]
([0, 1, 0], [0, 1, 0], [1, 0, 0]) (a*b)*c : [0 0 0] a*(b*c) : [-1  0  0]
([0, 1, 0], [0, 1, 0], [0, 0, 1]) (a*b)*c : [0 0 0] a*(b*c) : [ 0  0 -1]
([0, 1, 0], [0, 0, 1], [0, 0, 1]) (a*b)*c : [ 0 -1  0] a*(b*c) : [0 0 0]
([0, 0, 1], [1, 0, 0], [1, 0, 0]) (a*b)*c : [ 0  0 -1] a*(b*c) : [0 0 0]
([0, 0, 1], [0, 1, 0], [0, 1, 0]) (a*b)*c : [ 0  0 -1] a*(b*c) : [0 0 0]
([0, 0, 1], [0, 0, 1], [1, 0, 0]) (a*b)*c : [0 0 0] a*(b*c) : [-1  0  0]
([0, 0, 1], [0, 0, 1], [0, 1, 0]) (a*b)*c : [0 0 0] a*(b*c) : [ 0 -1  0]

Использование таблицы умножения вместо функции - это просто вопрос выражения таблицы в виде массива python и поиска m результата в массиве. Python индексирует массивы с целыми числами от 0 до length-1, и вы можете иметь массивы внутри массивов. Вам понадобится изоморфизм между вашей конечной группой G и {0,1,..., ||G||-1}

Другие вопросы по тегам