• No se han encontrado resultados

Autómatas: Automaton y ExtendedAutomaton

4.3. Estructuras de datos de inferencia XSD

4.3.3. Autómatas: Automaton y ExtendedAutomaton

Figura 7: Diagrama de clases UML de Automaton y ExtendedAutomaton

En nuestra solución, necesitamos almacenar los siguientes tipos de autómatas:

1. Autómatas de elementos: Durante el proceso de inferencia, necesitaremos describir la estructura de hijos admitida bajo un tipo complejo como un SOAs (Single Occurrence Automaton (28)) con soportes (24), tal y como explicaremos más adelante en la descripción de la clase ComplexType.

2. Autómatas de expresiones regulares: En la fase de conversión, en concreto, en la implementación del algoritmo REWRITE dada por la clase SoreConverter, necesitaremos almacenar y manejar un GFA (Generalized Finite Automaton [32]), cuyos nodos serán expresiones regulares.

3. Diagrama de Hasse de clases de equivalencia: En la fase de conversión, en concreto, en la implementación del algoritmo CRX en ChareConverter (y su extensión eCRX en EChareConverter), necesitaremos manejar el diagrama de

65

Hasse [32] sobre el que trabaja dicho algoritmo (véase el apartado 4.7.1 para más detalles). Este diagrama no es un autómata estrictamente hablando. Sin embargo, puede representarse empleando las mismas clases.

Para representar los casos 2 y 3, hemos definido la clase Automaton<E>, donde el parámetro de tipo E se refiere al tipo de los nodos del autómata. Dicho parámetro de tipo será RegularExpression en el caso 2 y EquivalenceClass en el caso 3 (véanse las respectivas descripciones en los apartados 4.3.5 y 4.3.4). Para el caso 1 hemos definido la clase ExtendedAutomaton que, como su propio nombre indica, extiende a Automaton<SchemaElement> para añadir algunas funcionalidades que tan solo serán necesarias en este caso concreto (nótese que los nodos de ExtendedAutomaton siempre serán de tipo SchemaElement).

Comencemos a describir la clase Automaton. Para almacenar los nodos del autómata empleamos un conjunto de elementos E llamado nodes. En cambio, para almacenar las aristas utilizamos una Table de Guava llamada edges, en la que la primera clave será el nodo de origen de la arista, la segunda clave será el nodo de destino de la arista y el valor será el soporte de dicha arista.

También almacenamos el nodo inicial y el nodo final en sendos atributos initialState y finalState. El nodo inicial y el nodo final son opcionales, deben aparecer también en el conjunto nodes y que, en caso de ser objetos de tipo SchemaElement, se espera que su espacio de nombres sea “http://dit.upm.es/xsdinferencer/pseudoelements” (no se obliga a ello para facilitar que la clase sea reutilizable en otros contextos, pero los diferentes componentes de nuestra solución sí lo presupondrán).

Contamos con operaciones básicas para añadir nodos, añadir aristas (bien incrementando su soporte unidad por unidad o estableciéndolo explícitamente), sustituir nodos, eliminar nodos y aristas, contar el número de nodos y/o aristas, consultar el peso de una arista o verificar si un autómata contiene todos los nodos o todos los nodos y aristas de otro.

Además de estas, contamos con otras operaciones más específicas de un grafo, que hacen que esta clase no sea una simple colección. Podemos averiguar qué aristas nacen o mueren en un nodo concreto y ver qué nodos pueden alcanzarse desde un nodo concreto (saltando de nodo en nodo a través de aristas que los unan, respetando la dirección de las mismas). También podemos comprobar si existen ciclos y hallar una ordenación topológica de los nodos (si se intentase hacer sobre un grafo con ciclos, se produciría una NonAcyclicGraphException).

Además, tenemos la operación “aprender palabra” (método learn()), que actualiza el autómata para que reconozca una nueva palabra dada, añadiendo todos los nodos que falten y todas las aristas necesarias (una entre el estado inicial y el primer símbolo de

66

la palabra, otra entre el último símbolo y el estado final y una que una cada símbolo con el siguiente).

Es importante señalar que dos autómatas se considerarán iguales si sus conjuntos de nodos y aristas son iguales y los soportes de todas las aristas coinciden. Sin embargo, se proporciona un método auxiliar para comparar autómatas sin tomar en consideración las aristas.

Una vez hemos explicado Automaton, pasamos a describir ExtendedAutomaton. La principal aportación de esta clase es que almacena información sobre cuantas veces aparece cada símbolo en cada palabra de las que dieron lugar al autómata, ya que esta información es necesaria para el correcto funcionamiento de CRX y eCRX (si bien puede suponer una sobrecarga innecesaria en la mayoría de situaciones en las que se usa un autómata).

Para ello, empleamos una tabla llamada sourceWordSymbolOccurrences, en la que la primera clave es un índice numérico que identificará a la palabra, la segunda clave es un objeto SchemaElement que identifica al símbolo y el valor es el número de veces que el símbolo de la segunda clave aparece en la palabra identificada por la primera clave. El método learn() se actualiza para que esta estructura se rellene apropiadamente.

Una vez rellena esa estructura, el autómata debe ser capaz de proporcionar dos informaciones a los algoritmos CRX y eCRX. Para ello, hemos de implementar algunos métodos en ExtendedAutomaton:

 Dado un factor de una CHARE (en forma de un objeto EquivalenceClass), el número mínimo y máximo de apariciones de un símbolo cualquiera en una misma palabra. El método encargado es getFactorSymbolMinMaxOccurrences().

 Dado un factor de una CHARE (en forma de un objeto EquivalenceClass), el número mínimo y máximo de apariciones de dicho factor, entendiendo como “número de apariciones del factor” la suma del número de apariciones de cada uno de los símbolos del factor. El método encargado es getFactorMinMaxOccurrences().

El contexto de uso de esta información se detallará en el apartado 4.7.1 - Conversión autómata-RE.

La otra gran aportación de esta clase proviene de lo que llamaremos nodos equivalentes. Por necesidades de implementación, los objetos SchemaElement se consideran iguales si el nombre, el espacio de nombres y el tipo son iguales. Sin embargo, en ocasiones es interesante comprobar si un autómata contiene elementos con el mismo nombre y el mismo espacio de nombres que otro dado, sin tener en cuenta el tipo. Denominamos elementos equivalentes a aquellos que tengan el mismo nombre y espacio de nombres. En ExtendedAutomaton, proveeremos métodos para

67

 Hallar el nodo del autómata que sea equivalente a uno dado (si existe).  Existe una arista entre nodos equivalentes a dos dados.

 Determinar si un conjunto de nodos equivalentes está presente en el autómata.

 Determinar si un autómata contiene nodos equivalentes a todos los de otro autómata.

 Determinar si un autómata contiene nodos equivalentes a todos los de otro autómata y las mismas aristas entre ellos.

Adicionalmente, podemos comprobar si dos autómatas tienen exactamente los mismos nodos ignorando sus tipos (es decir todos los nodos de uno son equivalentes a los del otro y viceversa) y las mismas aristas aunque sus soportes difieran.