Thérapie de groupe: identifier les groupes

17

Écrivez un programme qui détermine si la table de multiplication du magma fini donné représente un groupe. Un magma est un ensemble avec une opération binaire qui est fermée, cela signifie

  • pour tout a, b dans G, a * b est à nouveau dans G (Fermeture)

Soit (G, *) un magma. (G, *) est un groupe si

  • pour tout a, b, c dans G, (a * b) * c = a * (b * c) (associativité)
  • il existe un élément e dans G tel que e * a = a * e = a pour tout a dans G (Existence d'un élément neutre)
  • pour tout a dans G il y a ab dans G tel que a * b = b * a = e où e est l'élément neutre (Existence d'Inverse)

Spécifications

L'entrée est une chaîne de n ^ 2-1 caractères (un caractère pour chaque élément du magma, autorisé est 0-9, az) et représente simplement la table lue ligne par ligne, en omettant le nom de l'opérateur. Vous pouvez supposer que l'entrée représente un magma valide (cela signifie que chacun des éléments apparaît exactement une fois dans la ligne / colonne d'en-tête).

Exemple: nous avons ici le tableau de Z_4

+ | 0 1 2 3
-----------
0 | 0 1 2 3
1 | 1 2 3 0
2 | 2 3 0 1
3 | 3 0 1 2

La chaîne d'entrée sera 012300123112302230133012. (Ou si nous utilisons des symboles, cela pourrait aussi l'être nezdnnezdeezdnzzdneddnez). Sachez que la séquence des éléments dans la ligne et dans la colonne ne doit pas nécessairement être la même, donc la table de Z_4 pourrait également ressembler à ceci:

+ | 1 3 2 0
-----------
1 | 2 0 3 1
0 | 1 3 2 0
2 | 3 1 0 2
3 | 0 2 1 3

Cela signifie également que l'élément neutre n'est pas nécessairement dans la première colonne ou la première ligne.

S'il s'agit d'un groupe, le programme doit renvoyer le caractère représentant l'élément neutre. Sinon, il doit renvoyer une valeur falsifiée (distincte des valeurs 0-9 az)

Cas de test

Les non-groupes peuvent facilement être construits en modifiant simplement un chiffre de la chaîne ou en modifiant artificiellement les tables définissant une opération qui contredit l'un des axiomes du groupe.

Groupes

Banal

* | x
-----
x | x

xxx

Neutral Element: x

H (groupe quaternion)

* | p t d k g b n m 
-------------------
m | b d t g k p m n 
p | m k g d t n p b 
n | p t d k g b n m 
b | n g k t d m b p 
t | g m n p b k t d 
d | k n m b p g d t 
k | t b p m n d k g 
g | d p b n m t g k 

ptdkgbnmmbdtgkpmnpmkgdtnpbnptdkgbnmbngktdmbptgmnpbktddknmbpgdtktbpmndkggdpbnmtgk

Neutral Element: n

D_4

* | y r s t u v w x
-------------------
u | u x w v y t s r
v | v u x w r y t s
w | w v u x s r y t
x | x w v u t s r y
y | y r s t u v w x
r | r s t y v w x u
s | s t y r w x u v
t | t y r s x u v w


yrstuvwxuuxwvytsrvvuxwrytswwvuxsrytxxwvutsryyyrstuvwxrrstyvwxusstyrwxuvttyrsxuvw

Neutral Element: y

Z_6 x Z_2

x | 0 1 2 3 5 7 8 9 a b 4 6
---------------------------
0 | 0 1 2 3 5 7 8 9 a b 4 6 
1 | 1 2 3 4 0 8 9 a b 6 5 7 
2 | 2 3 4 5 1 9 a b 6 7 0 8 
7 | 7 8 9 a 6 2 3 4 5 0 b 1 
8 | 8 9 a b 7 3 4 5 0 1 6 2 
9 | 9 a b 6 8 4 5 0 1 2 7 3 
a | a b 6 7 9 5 0 1 2 3 8 4 
b | b 6 7 8 a 0 1 2 3 4 9 5 
3 | 3 4 5 0 2 a b 6 7 8 1 9 
4 | 4 5 0 1 3 b 6 7 8 9 2 a 
5 | 5 0 1 2 4 6 7 8 9 a 3 b 
6 | 6 7 8 9 b 1 2 3 4 5 a 0 

01235789ab46001235789ab4611234089ab6572234519ab67087789a623450b1889ab7345016299ab684501273aab6795012384bb678a0123495334502ab67819445013b67892a5501246789a3b66789b12345a0

Neutral Element: 0

A_4

* | i a b c d e f g h j k l
---------------------------
i | i a b c d e f g h j k l
a | a b i e c d g h f l j k
b | b i a d e c h f g k l j
c | c f j i g k a d l b e h
d | d h k b f l i e j a c g
e | e g l a h j b c k i d f
f | f j c k i g d l a h b e
g | g l e j a h c k b f i d
h | h k d l b f e j i g a c
j | j c f g k i l a d e h b
k | k d h f l b j i e c g a
l | l e g h j a k b c d f i

iabcdefghjkliiabcdefghjklaabiecdghfljkbbiadechfgkljccfjigkadlbehddhkbfliejacgeeglahjbckidfffjckigdlahbegglejahckbfidhhkdlbfejigacjjcfgkiladehbkkdhflbjiecgalleghjakbcdfi

Neutral Element: i

Non-groupes

Une boucle (groupe manquant d'associativité, ou quasi-groupe avec élément neutre)

* | 1 2 3 4 5
-------------
1 | 1 2 3 4 5 
2 | 2 4 1 5 3 
3 | 3 5 4 2 1 
4 | 4 1 5 3 2 
5 | 5 3 2 1 4

12345112345224153335421441532553214

Neutral Element: 1
(2*2)*3 = 4*3 = 5 != 2 = 2*1 = 2*(2*3)

Une boucle IP (depuis http://www.quasigroups.eu/contents/download/2008/16_2.pdf )

* | 1 2 3 4 5 6 7
-----------------
1 | 1 2 3 4 5 6 7
2 | 2 3 1 6 7 5 4
3 | 3 1 2 7 6 4 5
4 | 4 7 6 5 1 2 3
5 | 5 6 7 1 4 3 2
6 | 6 4 5 3 2 7 1
7 | 7 5 4 2 3 1 6

123456711234567223167543312764544765123556714326645327177542316

Neutral Element: 1
2*(2*4) = 2*6 = 5 != 7 = 3*4 = (2*2)*4

Monoid (par Quincunx, merci!)

Les monoïdes sont des magmas avec associativité et un élément neutre.

* | 0 1 2 3
-----------
0 | 0 1 2 3
1 | 1 3 1 3
2 | 2 1 0 3
3 | 3 3 3 3

012300123113132210333333

Neutral Element: 0

Un autre monoïde

(Multiplication mod 10, sans le 5) Nous n'avons évidemment pas d'inverses, et l'associativité est donnée par la multiplication modulo 10.

* | 1 2 3 4 6 7 8 9
-------------------
1 | 1 2 3 4 6 7 8 9
2 | 2 4 6 8 2 4 6 8
3 | 3 6 9 2 8 1 4 7
4 | 4 8 2 6 4 8 2 6
6 | 6 2 8 4 6 2 8 4
7 | 7 4 1 8 2 9 6 3
8 | 8 6 4 2 8 6 4 2
9 | 9 8 7 6 4 3 2 1

Neutral Element: 1   12346789112346789224682468336928147448264826662846284774182963886428642998764321
flawr
la source
Je pensais ajouter une autre table, beaucoup plus grande, juste pour le plaisir: ideone.com/823aRG
Justin
Juste pour le plaisir, voici un autre très gros qui enfreint la 0-9a-zrègle: ideone.com/vC0ewt
Justin
Pour celui qui ne connaît rien aux groupes, aux magmas, etc., les spécifications sont floues. Par exemple, les opérations sont-elles commutatives? (donc la table est redondante). En outre. la position du neutre dans la première ligne n'est pas liée au fait d'avoir le même ordre dans la ligne et la colonne: avec 10101010l'ordre est le même et le neutre est dans la dernière ligne et colonne
edc65
@edc Les groupes ne sont pas nécessairement commutatifs (les groupes commutatifs sont appelés abéliens). La définition d'un groupe est complète (il s'agit de la définition habituelle), tout élément supplémentaire fournirait une restriction supplémentaire. Dans ces tableaux, la multiplication avec l'élément neutre se trouve généralement dans la première ligne / colonne, et la séquence des éléments de la ligne / colonne d'en-tête est généralement la même, mais vous pouvez toujours écrire un tableau valide sans suivre ces conventions, qui c'est ce que je voulais inclure ici.
flawr
1
J'ai supprimé certains commentaires qui semblaient obsolètes. Veuillez m'informer de tout commentaire qui ne devrait pas être supprimé.
Martin Ender

Réponses:

4

Octave, 298 290 270 265 caractères

function e=g(s)
c=@sortrows;d=a=c(c(reshape(a=[0 s],b=numel(a)^.5,b)')');
for i=2:b a(a==a(i))=i-1;end;
a=a(2:b,2:b--);u=1:b;
e=(isscalar(e=find(all(a==u')))&&a(e,:)==u&&sum(t=a==e)==1&&t==t')*e;
for x=u for y=u for z=u e*=a(a(x,y),z)==a(x,a(y,z));end;end;end;e=d(e+1);

265: Suppression du descripteur de fonction inutile.

270: Après tout, la vérification que e==hpour e toujours satisfaisant e · a = a et h satisfaisant toujours a · h = a n'était pas nécessaire. Ce n'est pas possible pour eux d'être différents ( e · h =? ).

Les détails de l'explication de la solution ci-dessous sont toujours pertinents.


290:

function e=g(s)
c=@sortrows;d=a=c(c(reshape(a=[0 s],b=numel(a)^.5,b)')');
for i=2:b a(a==a(i))=i-1;end;
a=a(2:b,2:b--);u=1:b;
s=@isscalar;e=(s(e=find(all(a==u')))&&s(h=find(all(a'==u')'))&&sum(t=a==e)==1&&t==t')*e;
for x=u for y=u for z=u e*=a(a(x,y),z)==a(x,a(y,z));end;end;end;e=d(e+1);

La première ligne

c=@sortrows;d=a=c(c(reshape(a=[0 s],b=numel(a)^.5,b)')'); stocke simplement l'entrée dans la table nxn (avec zéro caractère à l'endroit de la marque d'opération), puis trie lexicographiquement les colonnes et les lignes, de sorte que les lignes et les colonnes reçoivent le même ordre:

+ | z a t b                        + | a b t z
-----------                        -----------
z | t b a z         becomes        a | t a z b
b | z a t b      ============>     b | a b t z
t | a z b t                        t | z t b a
a | b t z a                        z | b z a t

Maintenant, je remappe "a","b","t","z"à la norme 1, 2, 3, 4, afin de pouvoir indexer la table efficacement. Cela se fait par la ligne for i=2:b a(a==a(i))=i-1;end;. Il donne une table comme

0   1   2   3   4
1   3   1   4   2
2   1   2   3   4
3   4   3   2   1
4   2   4   1   3

, où nous pouvons nous débarrasser de la première ligne et colonne avec a=a(2:b,2:b--);u=1:b;:

3  1  4  2
1  2  3  4
4  3  2  1
2  4  1  3

Ce tableau a les propriétés données:

  • si l'élément neutre e existe, exactement une ( isscalar) ligne et une colonne ont la valeur du vecteur ligne u=[1 2 3 ... number-of-elements]:

s=@isscalar;e=(s(e=find(all(a==u')))&&s(h=find(all(a'==u')'))&&...

  • si chaque élément a a un élément inverse a ' , deux choses sont valables: l'élément neutre e n'apparaît qu'une fois par colonne et une seule fois par ligne ( sum(t=a==e)==1) et, pour satisfaire a' · a = a · a ' , les occurrences de e sont symétrique par rapport à la traductiont==t'

  • a · b peut être récupéré par simple t(a,b)indexation. Ensuite, nous vérifions l'associativité dans la boucle ennuyeuse:

for x=u for y=u for z=u e*=a(a(x,y),z)==a(x,a(y,z));end;end;end;

La fonction renvoie l'élément neutre de la façon dont il est apparu dans la table d'origine ( e=d(e+1)) ou un caractère nul si la table ne décrit pas un groupe.

pawel.boczarski
la source
2
Bravo et bien expliqué. Devrait retourner l'élément neutre au lieu de 1.
edc65
Corrigé, retourne maintenant la valeur appropriée.
pawel.boczarski
1
OCTAVE FTW =) Je ne suis pas sûr de deux choses (provenant de matlab), mais vous pouvez peut-être l'utiliser pour améliorer votre réponse: Est-ce que `a (f (a == a (i))) = i-1` pourrait être réduit à a(a==a(i))=i-1? Autre que cela, vous pouvez peut-être utiliser à la (...)^.5place de sqrt(...).
flawr
@flawr Merci, ils fonctionnent tous les deux en octave (version 3.8.1).
pawel.boczarski
6

Rubis, 401 ... 272

f=->s{n=(s.size+1)**0.5
w=n.to_i-1
e=s[0,w].split''
s=s[w,n*n]
m={}
w.times{(1..w).each{|i|m[s[0]+e[i-1]]=s[i]}
s=s[n,n*n]}
s=e.find{|a|e.all?{|b|x=m[a+b]
x==m[b+a]&&x==b}}
e.all?{|a|t=!0
e.all?{|b|x=m[a+b]
t||=x==m[b+a]&&x==s
e.all?{|c|m[m[a+b]+c]==m[a+m[b+c]]}}&&t}&&s}

Ceci est mon premier programme rubis! Cela définit une fonction lambda que nous pouvons tester en faisant puts f[gets.chomp]. Je reviens falsepour ma fausse valeur. La première moitié de la fonction consiste simplement à analyser l'entrée dans une carte, puis la seconde moitié vérifie les possibilités.

f=->s{
    n=((s.size+1)**0.5).to_i
    w=n-1
    e=s[0,w].split'' # create an array of elements of the potential group
    s=s[w,n*n]
    m={} # this map is what defines our operation
    w.times{
        (1..w).each{               # for each element in the row of the table
            |i|m[s[0]+e[i-1]]=s[i] # put the value into the map
        }
        s=s[n,n*n]
    }
    s=e.find{|a| # s is the identity
        e.all?{|b|
            x=m[a+b]
            x==m[b+a]&&x==b # is a the identity?
        }
    }
    e.all?{|a| # implicit return statement
        t = !0 # t = false
        e.all?{|b| # check for inverses
            x=m[a+b]
            t ||= x==m[b+a]&&x==s # t is now true if b was a's inverse
            e.all?{|c|
                m[m[a+b]+c]==m[a+m[b+c]] # check associativity
            }
        } && t
    }&&s
}
Justin
la source
5
Bienvenue aux merveilles du golf à Ruby! ;) nilest une valeur de fausse plus courte que false. Les fonctions peuvent être définies comme des lambdas q=->{abort'false'}(si elles prennent des paramètres, utilisez-les []pour les appeler à la place de ()). Je pense que cela .charsdevrait déjà vous donner un tableau, donc pas besoin de .to_a. Si vous n'avez pas besoin d'un saut de ligne, $><<un octet plus court que l' putsespace plus. Hash.newn'a pas besoin des parenthèses. C'est tout ce que je peux voir pour l'instant. Continuez! ;)
Martin Ender
La charschose est étrange. Quelle version de Ruby utilisez-vous?
Martin Ender
@ MartinBüttner 1.9.3
Justin
Ah, c'est vrai, j'ai regardé la documentation de 2.1.5.
Martin Ender
1
Vous pouvez remplacer Math.sqrt(...)par...**0.5 . Aussi, a if bpeut être réécrit: b&&apour éviter les deux espaces
Cristian Lupascu
4

JavaScript (ES6) 285 243 278

Exécutez l'extrait de code pour tester (étant ES6, il ne fonctionne que sur Firefox)

Modifier 2 correction de bogue. J'avais tort de trouver l'élément neutre, en vérifiant juste dans un sens. (Besoin de meilleurs cas de test !!!)

Éditer En utilisant une concaténation de chaîne plus simple au lieu d'un double index (comme @Quincunx), je ne sais pas à quoi je pensais. De plus, la vérification inverse simplifiée devrait toujours fonctionner.

F=t=>(
  e=t.slice(0,d=Math.sqrt(t.length)|0),
  t=t.slice(d).match('.'.repeat(d+1),'g'),
  t.map(r=>{
    for(v=r[i=0],
        j=e.search(v)+1, // column for current row  element
        r!=v+e|t.some(r=>r[j]!=r[0])?0:n=v; // find neutral
        c=r[++i];
       )h[v+e[i-1]]=c
  },h={},n=''),
  e=[...e],!e.some(a=>e.some(b=>(
    h[a+b]==n&&--d, // inverse
    e.some(c=>h[h[a+b]+c]!=h[a+h[b+c]]) // associativity
  )
  ))&&!d&&n
)
input { width: 400px; font-size:10px }
Click on textbox to test - Result : <span id=O></span><br>
<input value='...' onclick='O.innerHTML=F(this.value)'> (?)
<br>Groups<br>
<input value='nezdnnezdeezdnzzdneddnez' onclick='O.innerHTML=F(this.value)'> (n)<br>
<input value='ptdkgbnmmbdtgkpmnpmkgdtnpbnptdkgbnmbngktdmbptgmnpbktddknmbpgdtktbpmndkggdpbnmtgk' onclick='O.innerHTML=F(this.value)'> (n)<br>
<input value='yrstuvwxuuxwvytsrvvuxwrytswwvuxsrytxxwvutsryyyrstuvwxrrstyvwxusstyrwxuvttyrsxuvw' onclick='O.innerHTML=F(this.value)'> (y)<br>
<input value='01235789ab46001235789ab4611234089ab6572234519ab67087789a623450b1889ab7345016299ab684501273aab6795012384bb678a0123495334502ab67819445013b67892a5501246789a3b66789b12345a0'onclick='O.innerHTML=F(this.value)'> (0)<br>
Non groups <br>
<input value='12345112345224153335421441532553214' onclick='O.innerHTML=F(this.value)'> (FAIL)<br>
<input value='123456711234567223167543312764544765123556714326645327177542316' onclick='O.innerHTML=F(this.value)'> (FAIL)<br>
<input value='012300123113132210333333' onclick='O.innerHTML=F(this.value)'> (FAIL)<br>

edc65
la source
2

Haskell 391B

import Data.Maybe
import Data.List
o a b=elemIndex b a
l£a=fromJust.o a$l
a§b=[a!!i|i<-b]
f s|isJust j&&and(map(isJust.o h)s)&&and[or[p%q==e|q<-h]&&and[p%(q%r)==(p%q)%r|q<-h,r<-h]|p<-h]=[e]|True="!"where n=floor$(sqrt(fromIntegral$length s+1))-1;h=take n s;g=[s§[a..b]|(a,b)<-zip[1+n,2+n+n..][n+n,3*n+1..(n+1)^2]];v=s§[n,1+2*n..n+n*n];a%b=g!!(b£v)!!(a£h);j=o g h;e=v!!fromJust j

Maudis ceux import s!

import Data.Maybe
import Data.List

{- rename elemIndex to save characters -}
o a b=elemIndex b a

{- get the index of l in a -}
l£a=fromJust.o a$l

{- extract a sublist of a with indices b -}
a§b=[a!!i|i<-b]

f s |isJust j {-Identity-}
     &&and (map (isJust.o h) s) {-Closure-}
     &&and[
        or [p%q==e|q<-h] {-Inverse-}
        && and [ p%(q%r)==(p%q)%r | q<-h,r<-h ] {-Associativity-}
     |
        p<-h
     ]=[e]
    |True="!"
    where
    {-size-}    n=floor$(sqrt(fromIntegral$length s+1))-1
    {-horiz-}   h=take n s
    {-table-}   g=[s§[a..b]|(a,b)<-zip[1+n,2+n+n..][n+n,3*n+1..(n+1)^2]]
    {-vert-}    v=s§[n,1+2*n..n+n*n]
    {-operate-} a%b=g!!(b£v)!!(a£h)
                j=o g h {-index of the first row identical to the top-}
    {-ident-}   e=v!!fromJust j

Explication

f::String->String mappe la chaîne sur e::Char l'élément d'identité ou !.

La whereclause crée un tas de variables et de fonctions, que j'ai commentées;v::[Int]est la liste verticale des éléments, h::[Int]celle horizontale.

%::Char->Char->Char applique l'opération de groupe à ses arguments.

g::[[Int]]est la table de groupe (pour déréférencer avec %)

j::Maybe Intcontient l'index de l'identité vs'il existe, sinon Nothing, c'est pourquoi isJust jla condition est fpour l'identité.

alexander-brett
la source
Pouvez-vous expliquer un peu ce qui se passe ici?
2015
J'ai ajouté quelques commentaires, mais l'essentiel est «d'appliquer les tests à la table de groupe». Notez que {- -}c'est un commentaire. Avez-vous des questions plus précises, ou est-ce que cela clarifie les choses?
alexander-brett
Merci. Je suppose que pour vraiment le comprendre, j'aurais d'abord besoin d'apprendre Haskell :-)
xebtl