Práctica - Semana 06 Homomorfismos, Isomorfismos y

Anuncio
Universidad Simón Bolívar
Departamento de Computación y Tecnología de la Información
CI2527 Estructuras Discretas III
SeptiembreDiciembre 2014
Práctica - Semana 06
Homomorsmos, Isomorsmos y Grupos Cíclicos Continuación.
En esta práctica continuaremos practicando los conceptos asociados a homomorsmos, isomorsmos y grupos cíclicos.
0.
¾Qué se ha visto hasta ahora en la teoría?
• Teorema de Lagrange.
• Homomorsmos e Isomorsmos.
• Grupos Cíclicos.
1.
Implementemos las ideas.
Haskell está centrado en dos conceptos principales. En primer lugar, las funciones. Pero estas
funciones se hacen interesantes es a través de un muy completo sistema de tipos. Los tipos juegan
un papel protagónico al usar un lenguaje como Haskell y el mismo tiene muchas facilidades para
la denición de nuevos tipos (en el Laboratorio de Lenguajes de Programación I se explorarán a
mayor profundidad).
Consideremos la siguiente denición para un predicado de dos argumentos que decide si el
primero es menor o igual que el segundo.
pred_menor_o_igual x y = x <= y
¾Cómo sería la rma de este predicado?
Es tentado decir que es pred_menor_o_igual :: a -> a -> Bool, pero tal rma no estaría
completa y, si la agregamos al predicado, Haskellno aceptará el programa. ¾Entonces, qué le
falta?
El predicado funciona sobre cualquier tipo, si, pero siempre y cuando ese tipo soporte la
operación <=. Por lo tanto, la rma del predicado se completa de la siguiente forma:
pred_menor_o_igual :: (Ord a) => a -> a -> Bool
1
1.1.
Programando con clase.
La forma en que se le dijo a Haskell que es posible aplicar <= sobre los elementos fue agregando
el prólogo Ord a a la rma de la función. A Ord y otros similares como Eq (para comparaciones
por igualdad), Show (para imprimir por pantalla), Bounded (para mínimo y máximo), etc., se les
conoce como clases de tipos.
Además de las que vienen con Haskell, es posible crear clases de tipos propias. Estas clases
sólo proponen la rma de las funciones que todo tipo de esa clase debe implementar (aunque es
posible dar deniciones por defecto de las mismas).
Como ejemplo, creemos una clase de tipos que soporten elevar al cuadrado:
class Duplicable a where
cuadrado :: a -> a
Nótese que sólo se especicó la rma de cuadrado y no se dio una implementación.
¾Cómo agrego miembros a esta clase de tipos?
Haciendo instancias. Esto es, diciendo cómo se comporta la función cuadrado para el tipo
deseado. Por ejemplo, agreguemos a los enteros:
instance Duplicable Integer where
cuadrado = (^2)
½Listo! Hagamos ahora lo mismo con listas genéricas.
instance Duplicable [a] where
cuadrado x = x ++ x
Ejercicios:
1. Realice una instancia de la clase Duplicable para booleanos, tal que el resultado siempre
sea True.
2. Construya una clase de tipos Restable que soporte la función resta (toma el primer
argumento y le quita el segundo).
(a) Realice una instancia de la clase Restable para enteros.
(b) Realiza una instancia de la clase Restable para listas (que se comporte como la resta
de conjuntos, conservando el orden).
2
1.2.
Grupoides, Semigrupos, Monoides y Grupos, reloaded.
Las rmas algebraicas en realidad tratan de dar estructura y propiedades a un conjunto de fondo,
llamado carrier.
En prácticas pasadas ya hemos visto que la noción de un tipo es similar a la de un conjunto.
Por lo tanto, podemos denir estructuras algebraicas sobre tipos.
½Eso lo hace ideal para Haskell!
Podemos usar las clase de tipos para darle la estructura que queremos a estos tipos.
Un grupoide es un conjunto (o tipo) base, junto con un operador binario cerrado.
Podemos representar este tipo de estructura en Haskell con una clase de tipos:
Grupoides:
class Grupoide c where
(<+>) :: c -> c -> c
Creamos un operador <+> que sólo por su rma ya es cerrado en el tipo c.
A continuación podemos empezar a agregar tipos a esta clase. Por ejemplo, podemos agregar
al tipo entero:
instance Grupoide Integer where
(<+>) = (+)
Hemos agregado a los enteros un operador <+> que se comporta como la suma. Así, los enteros
y este operador vienen a representar el grupoide aditivo de los enteros.
Un semigrupo es un Grupoide donde se exige que el operador sea asociativo.
Para que un tipo pueda ser aumentado a un semigrupo, este debe ser un grupoide y además
soportar comparaciones por igualdad (con el objetivo de comprobar la propiedad asociativa).
Semigrupos:
Podemos representar este tipo de estructura en Haskell con una clase de tipos:
class (Grupoide c, Eq c) => Semigrupo c
Aquí ocurrieron dos cosas diferentes:
• Creamos una clase de tipos condicionada. Al igual que para las funciones, en la que se
coloca un prólogo a la rma, se puede colocar un prólogo a la denición de la clase.
3
• No necesitamos incluir el where, ya que la rma de la estructura algebraica entre grupoides
y semigrupos no cambia. Lo que diferencia uno del otro es la propiedad asociativa del
operador.
Podemos ahora implementar una propiedad sobre tipos que sean semigrupos que verique la
asociatividad del operador:
prop_asociativa :: (Semigrupo c) => c -> c -> c -> Bool
prop_asociativa a b c =
a <+> (b <+> c) == (a <+> b) <+> c
Nótese que como se agregó Grupoide c como prólogo de la rma, la operación <+> se hizo
disponible.
Para incluir a los enteros en la clase Semigrupo, basta con expresarlo directamente. Esto, ya
que los enteros ya son miembros de Grupoide y Eq.
instance Semigrupo Integer
Un monoide es un semigrupo, en donde uno de los elementos del carrier es considerado neutro o identidad.
Monoides:
Podemos representar este tipo de estructura en Haskell con una clase de tipos:
class (Semigrupo c) => Monoide c where
e :: c
Podemos ahora implementar una propiedad sobre tipos que sean monoides que verique que
el elemento escogido es en verdad neutro:
prop_neutro :: (Monoide c) => c -> Bool
prop_neutro a =
a <+> e == a
&&
e <+> a == a
Para incluir a los enteros en la clase Monoide se debe decir quién es su elemento neutro (con
respecto a la suma, que fue como denimos su grupoide).
instance Monoide Integer where
e = 0
4
Un grupo es un monoide en el que cada elemento del carrier tiene un inverso. Esto
es, existe una función que toma cada elemento del carrier y lo lleva a algún elemento que sea su
inverso.
Grupos:
Podemos representar este tipo de estructura en Haskell con una clase de tipos:
class (Monoide c) => Grupo c where
inv :: c -> c
Podemos ahora implementar una propiedad sobre tipos que sean grupos que verique que la
función construya inversos:
prop_inverso :: (Grupo c) => c -> Bool
prop_inverso a =
a <+> (inv a) == e
&&
(inv a) <+> a == a
Para incluir a los enteros en la clase Grupo se debe decir quién es su función para inversos
(con respecto a la suma, que fue como denimos su grupoide).
instance Grupo Integer where
inv = negate
La función negate toma un entero y produce el negativo del mismo.
Ejercicios:
1. Considere el grupo hB, ∨, f alse, ¬i, de los booleanos con la disyunción, elemento neutro
f alse y la negación como inverso.
(a) Incluya a los booleanos como miembros de Grupoide con operador ∨.
(b) Sobre eso, incluya a los booleanos como miembros de Semigrupo.
(c) Sobre eso, incluya a los booleanos como miembros de Monoide, con elemento neutro
f alse.
(d) Sobre eso, incluya a los booleanos como miembros de Grupo, con ¬ como inverso.
2. Considere el monoide hString, ++, ""i, de las cadenas de caracteres con la concatenación
y la cadena vacía como elemento neutro.
(a) Incluya a las cadenas de caracteres como miembros de Grupoide con operador ++.
(b) Sobre eso, incluya a las cadenas de caracteres como miembros de Semigrupo.
5
(c) Sobre eso, incluya a las cadenas de caracteres como miembros de Monoide, con la
cadena vacía como elemento neutro.
(d) ¾Es posible aumentar esta estructura tal que sea un grupo? ¾Cómo sería el inverso de
ser posible?
1.3.
¾Y las tablas?
Muchas veces es deseable tener una tabla de operadores explícita, sobre elementos abstractos
como a, b, c, etc. Esto también es posible de construir en Haskell y veremos a continuación el
camino.
Supongamos que queremos implementar el grupoide hG, ⊕i, que tiene G = {a, b, c, d} como
carrier y el operador ⊕ está denido por la siguiente tabla:
⊕
a
b
c
d
a
a
b
c
d
b
b
c
d
a
c
c
d
a
b
d
d
a
b
c
En primer lugar, debemos crear un tipo que represente al conjunto G. Eso lo podemos hacer
a través de una denición de datos:
data G = A | B | C | D
Además, es conveniente poder imprimir miembros de este tipo y poder compararlos por igualdad. Para este tipo de clases, Haskell trae implementaciones por defecto. Para utilizarlas, basta
con agregar deriving y las clases que se desea instanciar.
data G = A | B | C | D
deriving (Eq, Show)
Crear la tabla de operadores es verboso, en el sentido que hay que escribir bastante (contrario
a lo que hemos visto en Haskell). Existen maneras de escribir estas tablas de una forma más
compacta, pero hace falta ahondar mucho más en el lenguaje para utilizarlas.
instance Grupoide G where
A <+> A = A; A <+> B = B;
B <+> A = B; B <+> B = C;
C <+> A = C; C <+> B = D;
D <+> A = D; D <+> B = A;
A
B
C
D
<+>
<+>
<+>
<+>
C
C
C
C
=
=
=
=
C;
D;
A;
B;
A
B
C
D
<+>
<+>
<+>
<+>
D
D
D
D
=
=
=
=
D
A
B
C
Nota: El punto y coma que aparece es una manera sintáctica de hacerle creer a Haskell que
se ha saltado de linea. De esa forma pudimos escribir la función en forma de tabla y no como
16 las.
6
Ejercicios:
1. Incluya a G como miembro de la clase Semigrupo.
2. Sobre eso, incluya a G como miembro de la clase Monoide (debe averiguar el neutro).
3. Sobre eso, incluya a G como miembro de la clase Grupo (debe averiguar los inversos).
2.
Ejercicios de la práctica.
1. Dado el grupo G = hZ12 , ⊕12 , 0, (a)−1 i donde ⊕12 está denido por: a ⊕12 b = a + b
(a) Dé el orden de todos los posibles subgrupos de G.
(b) Para el subgrupo no trivial de menor tamaño halle las clases laterales de ese subgrupo
en G.
2. Sea h un homomorsmo de un grupo hG, ∗, e, ()−1 i en un grupo hG0 , ∗0 , e0 , ()−1 i. Demuestre:
0
(a) Si e es la identidad de G entonces h.e es la identidad de G0 .
(b) Si a ∈ G entonces h(a−1 ) = (h.a)−1 es la inversa en G0 .
(c) Si hH, ∗, e, ()−1 i es un subgrupo de hG, ∗, e, ()−1 i, entonces h(H) es un subgrupo de
0
hG0 , ∗0 , e0 , ()−1 i
0
0
(d) Si hK 0 , ∗0 , e0 , ()−1 i es un subgrupo de hG0 , ∗0 , e0 , ()−1 i, entonces h−1 (K 0 ) es un subgrupo de hG, ∗, e, ()−1 i.
3. Diga si hay o no un isomorsmo de G = hZ, +, 0, −ai en G0 = hR, +, 0, −ai. Justique su
respuesta.
4. Sea h una función de hZ, +, 0, −ai en h3Z, +, 0, −ai denida por h.n = 3n. Diga si h es un
isomorsmo. (3Z es el conjunto de todos los múltiplos de 3).
5. ¾Es el grupo hZ, +, 0, −ai isomorfo al grupo hQ, +, 0, −ai?
6. Si hG, ∗, ei es un grupo cíclico, demuestre que todo subgrupo de hG, ∗, ei es cíclico.
7. Dado el grupo G = hZ24 , ⊕24 , 0, ()−1 i, para los grupos H = h4i y K = h8i, halle las clases
laterales de H en G y de K en G.
3.
Lecturas adicionales:
• Capítulo 4 de las guías del prof. Vicente Yriarte.
• Capítulo 3 de Learn You A Haskell..
4.
Tarea:
• Completar los ejercicios y demostraciones que no se hayan hecho en clase.
• Descargar el archivo semana06.hs y completar los ejercicios faltantes.
Ricardo Monascal / SeptiembreDiciembre 2014
7
Descargar