jueves, 16 de octubre de 2014

He alcanzado el siguiente nivel de abstracción

En la publicación del 22/04/2012 ya explicaba a lo que me estoy refiriendo.

Por cada tipo de palabra e incluso subtipo se tenía que programar una lista específica.

El siguiente nivel pretendía usar una lista común a todas independientemente de sus propiedades.

En su momento propuse usar un árbol de propiedades, y no iba mal encaminado.


Mediante árboles de propiedades:

La vez anterior no me fue posible porque no tenía el apoyo de un autómata:

Ya hemos hablado de que el autómata ya era capaz de reconocer naturales, enteros o reales, entre otros muchos más.  Ya he mencionado tres propiedades. Si se organizan en forma de árbol podríamos pensar en uno del que desde la raíz cuelga un nodo etiquetado con número matemático,  y de éste otros tres nodos con las propiedades mencionadas.

La estructura de datos cuyo elemento básico Cadena compuesta por la cadena de texto, el tipo y posteriormente subtipo, pasan a desaparecer éstos últimos y en su lugar el árbol de propiedades específico de la cadena.

Entonces, dada una cadena, primero consulta si ya existe en la ED. En caso contrario el autómata reconoce la forma mediante ERs y nos dice las propiedades.  Por ejemplo,  para '1' nos dirá que se trata de un dígito, número natural,  número entero y número matemático. Sin embargo para '12.7' nos dirá que se trata de un número real y número matemático. Se guarda la información en la ED.

La ED ya existente nos proporciona encontrar una cadena concreta y a su vez obtener su árbol específico de propiedades. Ahora se le añade un árbol genérico de propiedades en la que en cada nodo hay una lista de cadenas con todas las cadenas con una misma propiedad. Todo entrelazado con la anterior ED.


Mediente un grafo y listas de propiedades:

Implementé todo lo descrito anteriormente y llegó a funcionar, el problema era que no era automático, es decir, hay que introducir las ER y luego generar manualmente el árbol global de propiedades basándonos en las ER. Al ser un árbol, no todas las propiedades se podían introducir

Lo llevé a un punto más allá. La solución fue cambiar en la cadena el árbol de propiedades por una simple lista de propiedades (que justo da la ED ya existente al reconocer una ER) y el árbol global de propiedades por un grafo de propiedades.

El resultado es que conforme se insertan las ERs en la ED se va generando el grafo automáticamente.


Evolución:

La cadena ha pasado de tener un campo tipo y después añadirsele otro llamado subtipo.

El la ED estaba organizado paralelamente a los diccionarios especiales, unas listas específicas por cada tipo o subtipo.

La siguiente evolución fue gracias al potente motor de los autómatas. Éste nos puefe informar de las propiedades de una cadena si se insertan las ERs correctas. Para organizar todo, se introduce el concepto de árbol de propiedades. Uno global en conjunto con la ED ya implementada (sin las listas de tipos) y otro específico en cada cadena sustituyendo al tipo y subtipo.

Funcionaba pero se quedaba corto. Es al introducir un grafo de propiedades como estructura global y las listas de propiedades en las cadenas cuando de verdad se ha automatizado todo en lo referente de gestion y almacenaje de las cadenas trabajadas por los autómatas dándonos la posibilidad de consultar por cadena o incluso obtener listados completos de cadenas que cumplan propiedades.

Esto implica que el mayor peso recae sobre el autómata. Las ERS deben de ser correctas, sin fallos de paréntesis y simplificadas.  Aún así a más ERs más tarda en arrancar aunque luego las consultas sean inmediatas.

El autómata es dinámico hasta cierto punto. Se pueden insertar tantas NUEVAS ERS en tiempo real como queramos. Pero al modificar ya alguna se tiene que recalcular por completo (o por lo menos en la actualidad).

Le he añadido un simple JFrame como ventana principal. Tiene un area de texto donde aparece todo lo que se va haciendo, tanto lo que el usuario escribe como los resultados que da la aplicación. Otra area de texto donde el usuario escribe y una barra de proceso. Para que ésta funcione correctamente he modificado el código de generación de los autómatas y carga de información en hilos para que trabajen de modo concurrente. 

Tengo que seguir modificando y añadiendo funcionalidad a una ED cada vez más robusta:

Con vista a guardar la información procesada (ha perdido esta funcionalidad al cambiar las estructuras) he pensado en añadir un booleano en los nodos de propiedades para que me informe si en su lista de cadenas hay alguna nueva desde la última vez que se guardó todo. Las nuevas ER también hay que guardarlas pero siempre respetando el orden en el que fueron creadas. 

Al introducir por ejemplo con las ERs de los numerales introducidos:

menos quince con siete entre dos

El automata lo reconoce y nos dice que es:

Numeral, numeral fraccionario. 

E inserta en los nodos del grafo del nuneral y del numeral fraccionario la cadena completa. 

El siguiente cambio sería que almacenase en el grafo lo que va reconociendo parcialmente:

Quince, siete, dos, menos quince y menos quince con siete. 

Quince, siete y dos: numeral natural, numeral entero positivo, numeral.

menos quince: nuneral entero negativo,  numeral.

menos quince con siete: numeral real positivo,  numeral.

Todo esto ya lo hace el autómata y el grafo tiene todos sus nodos ya preparados para manejar todas las propiedades.  Ahora sólo falta hacer que según reconozca cada elenento lo inserte en el grafo sin esperar al resultado final. 

Al fin y al cabo,  son expresiones regulares reconocidas que nos dan propiedades. 

También quiero, cuando me vea con fuerzas, hacer que descomponga la generación de autómatas en diferentes hilos,  uno por cada sigo +, para que de forma paralela trabaje e intentar reducir el tiempo de arrancado y posteriormente,  modificado de ERs ya procesadas. 

domingo, 12 de octubre de 2014

Realizando cambios...

Buenos días. Hace casi once meses que no publico nada pero entre el trabajo y los estudios no he tenido mucho tiempo para una de mis aficiones,  programar.

Lo primero disculparme de los continuos cambios en el código ya funcional.  Un programador profesional antes de ponerse a escribir código, habrá pasado meses modelando su aplicación con un estudio previo de todas las clases y métodos que le irán haciendo falta.  De esta manera tendrá las ideas más claras y sabrá que quiere exactamente al desarrollar su código y no estará realizando cambios estructurales como en mi caso y el tiempo invertido en ese estudio previo lo verá pronto recompensado.

Pero yo en este proyecto no quiero aplicarlo. Precisamente pretendo explicar razonadamente y mediante fallo y error el por qué del código. De este modo el lector se sentirá más integrado al ir formándose en él la estructura y concepto del proyecto a la vez que en mí, cosa bien distinta sería si simplemente me dedicara a explicar un código ya finalizado.

Después de toda esta parrafada estos son los cambios más importantes:

Repartición del peso del autómata

La aplicación poseía sólo un gran autómata que reconocía los comandos, números matemáticos y secuencias de palabras. El problema de esto eran los símbolos, es decir, trabaja con números, letras otros símbolos y cada vez que se le añade otra ER realiza su tabla de transiciones para todos estos símbolos independientemente de que la nueva ER los use.

Al terminar de desarrollar los autómatas propuse repartir el peso en otros autómatas según los símbolos. Lo llevé a cabo:

- Autómata Comandos
- Autómata Matemático
- Autómata Alfabético
- Autómata Otros Símbolos
- Autómata Relaciones Sintácticas
- Autómata Dinámico

De este modo las ER que comienzan por # al autómata de comandos, las que empiezan por $ al de relaciones sintácticas, números y símbolos matemáticas al matemático, las ER que representan palabras al alfabético y los que contienen otros símbolos como los interrogantes,  exclamaciones, etcétera,  al de otros símbolos.

El dinámico estaría destinado a las ER que introduciría el usuario en tiempo de ejecución.

Al cargar los autómatas tardaba un poco y algo de ahorro en memoria, pero no muy significativo. Encontré más inconvenientes que ventajas:

- Para comprobar una ER se ha de ir haciéndolo secuencialmente por todos los autómatas para que en el peor de los casos no pertenezca a ningún autómata después de realizar seis consultas.

- Las ER ya pertenecientes autómata no pueden ser utilizadas en otro autómata distinto y si quiere hacerse ha de duplicarse la ER recursivamente volviendo el problema.

- Se pierde el dinamismo para introducir nuevas ER en tiempo de ejecución.

He optado por el camino intermedio:

- Autómata Comandos
- Autómata Relaciones Sintácticas
- Autómata General

De este modo se conserva el dinamismo mediante el autómata general siendo los otros dos estáticos.

Base de datos para guardar la información

Desde el principio mantuve la política de no usar una base de datos simplemente por admitir que sería un desperdicio al no aprovechar su potencial en sus consultas, concurrencia, etcétera y sólo utilizarlo como almacén.

Pero tras mucho deliberar, al final he cedido. Por dos razones:

- Tener la información organizada en una única base de datos en lugar de numerosos ficheros .dat con dicha información sin ninguna estructura.

- Visualización de los datos que se van almacenando para comprobar que todo va como debe de hacerlo.

Aún así sólo me limitaré a cargar los datos al iniciar el programa y a actualizar las tablas al finalizar, sin realizar consultas o actualizaciones en tiempo de ejecución ya que el que debe organizar la información con el programa en marcha, es la propia aplicación.

Esto conlleva la modificación del todo el código que cargaban y guardaban las listas de cadenas.

Eliminación de función de cadena

Una misma palabra puede funcionar como determinante en unos casos o como pronombre en otros, por ejemplo. La palabra morfológicamente hablando es la misma, es al darle un sentido sintáctico cuando adquiere su funcionalidad.  Para evitar reiteración de cadenas y lo peor de todo, con su función sin definir en muchos casos esperando a la fase sintáctica, he optado por quitar ese parámetro. Más adelante se le dará su funcionalidad de otro modo.

Reorganización de tipos: subtipos

Un número natural, un número entero o incluso un número fraccionario tiene en común que es un número pudiéndose tratar del mismo modo en muchos casos.

Extendiendo este concepto al resto de palabras, la mayoría de tipos pueden clasificarse mejor en subtipos.

Trabajo laborioso al tener que modificar las cadenas, listas e incluso las interfaces.

Replanteamiento de los números

He separado la representación de un número matemáticamente hablando de su cardinal.

Un número matemáticos no tiene género.

Dos cardinales pueden representar el mismo número matemáticos y ser distintos:

- Cardinal: Uno, número matemático: 1
- Cardinal: Una, número matemático: 1
- Cardinal: Un, número matemático: 1

Tres cardinales naturales hacen referencia a un mismo número natural,  esto significa que un cardinal natural se refiere a un único número natural y un número natural puede ser referido por varios cardinales naturales.

La diferencia entre estos cardinales es el género.

La cosa se puede conplicar más si pensamos que 1/1, 2/2, tres entre tres, etcétera también representan a 1.

Voy a intentar explicar cómo trabaja con los números naturales y sus correspondientes cardinales naturales:

Número natural: lo abrevio con N.
Cardinal natural: con C.

- Un N tiene una lista L de Cadenas que le hacen referencia.

- Un C tiene un número matemático (en este caso natural) único al que se refiere,  además del género y número.

Algoritmo para la inserción de un natural:

1. Buscar N en la estructura de datos por si ya estuviera tratado con anterioridad.
1.1. En el caso de que exista se recupera y será con este con el que trabajaremos en los siguientes pasos.

1.2. Y en el supuesto de que no exista, se crea e inserta en la estructura de datos y se trabajará con éste.

2. Se calcula el C para el género Masculino, otro Femenino y el Neutro.  Para simplificar la explicación no se va a distinguir entre estos, pero todo lo que se haga con C se hará por triplicado.

3. Buscar C en la estructura general de datos.

3.1. De forma idéntica que con N, si C existe se trabajará con ese objeto.

3.2. Y si no existe, se crea, se inserta y se trabaja con el nuevo.

4. Referenciado entre N y C:

4.1. C (número matemático) ← N

4.2. Si en la lista de N no hay referencia a C entonces Lista (N)← C

Algoritmo para la inserción de un cardinal natural:

1. Independientemente del género de C obtenemos su N.

2. Con N se puede usar directamente el algoritmo anterior.

Este concepto se amplía con el resto de tipos de números y cardinales. Aunque se complica, la base es la misma.

martes, 21 de enero de 2014

Breve explicación de los autómatas del proyecto


Introducción

Esta entrada del blog pretende explicar brevemente las ideas que he plasmado en el código del Proyecto GR para tratar expresiones regulares.

El tratamiento de autómatas es sólo una parte del Proyecto GR. Este proyecto pretende definir una estructura de datos que sea capaz de ir reconociendo la sintaxis del castellano. Intenta que la aplicación realice consultas a internet para averiguar aquella palabra que no tenga previamente procesada debiendo de obtener su tipo: adjetivo, sustantivo, pronombre… sus características como son el género, número… sus definiciones, etc. Toda esta información se va almacenando en una estructura de datos muy compleja que no viene al caso.

Caí en la cuenta que es un desperdicio de memoria y tiempo tener que trabajar con números por ejemplo ya que son infinitos y el valor de un número no hace falta estar consultándolo a internet, 1 es 1.

Esto me recordó a la asignatura de Autómatas y me puse como reto programar los algoritmos correspondientes para poder trabajar con Autómatas No Deterministas Landa, Autómatas Deterministas y Autómatas Deterministas Mínimos.

Pido disculpas si no utilizo correctamente los términos o nombres de los autómatas, hace años que di la asignatura y todo se olvida.

Estructura básica

El trabajo se reparte en dos bloques. Dada una cadena de texto se le pasa como parámetro al primer bloque que corresponde a los autómatas que realizarán el reconocimiento de dicha cadena para ver si cumplen alguna expresión regular de las programadas previamente. En el caso de que así sea nos devolverá el o los estados finales a los que ha llegado. Dichos estados finales llevarán asociado el nombre de la expresión regular reconocida. Ya sabiendo los nombres de las expresiones reconocidas, el segundo bloque les dará significado. Por ejemplo:

Teniendo las ER correspondientes a lo que es un dígito, un número natural, un número entero y un número real, si como cadena de entrada se le pasa al primer bloque -8 nos devolverá un único estado final correspondiente a número entero. Si a este mismo ejemplo se le pasa 9 nos dirá que se trata de un dígito, número natural y número entero. El segundo bloque nos diría que el valor del dígito 9 es 9 por ejemplo. Aquí parece evidente, ¿pero qué ocurre con un caso más complejo como pueden ser los números romanos…? El primer bloque tendría una expresión regular indicándole que un número romano es aquel que está formado por una sucesión de símbolos romanos como son I, V, X, L, C, M, () para indicar miles. El autómata reconocería una entrada como puede ser XX, pero es el segundo bloque el que lo interpreta y nos dice que se trata de un natural cuyo valor es 20.

Me voy a centrar en el primer bloque.

Se utilizan las siguientes estructuras de datos para trabajar en el primer bloque: ANDLT, ADFMínimo y dos diccionarios, uno que utiliza los nombres de las ER para su reconocimiento y otro directamente la ER. En ambos casos los nodos hoja apuntan a un ADFMínimo.

ANDLT

En su estructura se almacena la ER propiamente dicha, el nombre que se le ha dado, los símbolos que utiliza, la tabla de transiciones y los estados finales.

Por Ejemplo:

ER: 0+1+2+3+4+5+6+7+8+9

Nombre: digito

Símbolos: {0,1,2,3,4,5,6,7,8,9, L} L corresponde a Landa

Tabla de transiciones:

Q0 con L⇨Q0, Q1, Q3, Q5, Q7, Q9, Q11, Q13, Q15, Q17, Q19

Q1 con 0 ⇨Q2

Q2 con L ⇨Q21, Q21 estado final, 0 es un dígito

Q3 con 1 ⇨Q4

Q4 con L ⇨Q21, Q21 estado final, 1 es un dígito

Todo aquello que no esté en la tabla de transiciones el algoritmo lo conduce al estado Q-1, es decir, al estado Error.

En este ejemplo sólo hay un estado final Q21, pero se da el caso de que haya más de uno.

AFDMínimo

La estructura es semejante a la de los ANDLT sólo que únicamente hay un estado final, no tiene transiciones Landa y el número de estados es el mínimo.

Diccionarios

Como ya se ha comentado en la estructura de datos hay dos diccionarios. Uno hace las búsquedas por el nombre de la expresión regular, en el ejemplo sería digito y otro busca la propia expresión regular, que sería 0+1+2+3+4+5+6+7+8+9. Ambos nodos hoja de sus correspondientes diccionarios apuntan a la misma AFDMínimo en memoria.

¿Para qué sirven?

Si ya tiene en memoria el ADFMínimo de un dígito, para definir un número natural simplemente en la ER hay que decir:

ER: (digito)(digito)*

Nombre: natural

El diccionario de ADFMínimos se actualiza con (digito)(digito)* y el diccionario de Nombres de ER se actualiza con natural.

Para realizar su ADFMínimo va reconociendo y trabajando de modo recursivo la ER:

Encuentra ( y busca el siguiente ) trabaja con el contenido entre ambos símbolos.

Digito lo localiza en el diccionario de nombres de ER, con lo que ya tiene la tabla de transiciones mínima.

Encuentra ( y busca el siguiente ) pero se encuentra * seguido.
Vuelve a localizar en el diccionario de nombres de ER.

Genera un ANDLT concatenando la primera ER con la segunda ER teniendo en cuenta la *.

Genera un AFDMínimo a partir del ANDLT y actualiza los diccionarios.

Usando los diccionarios nos permite realizar ER más complejas al poder hacer sustituciones.

Estructura global

Un ANDLT  lo une todo. Es decir, para cada nueva ER se genera un AFDMínimo usando los diccionarios generando un estado final correspondiente. El ANDLT global lo inserta en su estructura uniéndolo con una transición Landa.

Ejemplo de inserción de nuevas ER:

Inicialmente ANDLTGlobal vacío.

Nueva ER: Digito 0+1+2+3+4+5+6+7+8+9

AFDMínimo: estados [q0, q1], estado final [q1], símbolos {0,1,2,3,4,5,6,7,8,9}

Actualiza diccionario de AFD con 0+1+2+3+4+5+6+7+8+9.

Actualiza diccionario de nombres ER con digito.

Inserta en ANDLTGlobal: estados [q0,q1,q2], estado final [q2 (digito)], símbolos {0,1,2,3,4,5,6,7,8,9,L} donde las transiciones de q1 y q2 son copiadas del AFDMínimo de digito respetando los índices de ANDLTGlobal y q0 a q1 mediante una transición Landa.

Nueva ER: Natural (Digito)(Digito)* que significa uno o infinitos dígitos uno tras otro.

AFDMínimo: estados [q0, qn], estado final [qn], símbolos {0,1,2,3,4,5,6,7,8,9}
Actualiza diccionario de AFDMínimo con (0+1+2+3+4+5+6+7+8+9)(0+1+2+3+4+5+6+7+8+9)*. Para su cálculo busca el contenido de los paréntesis en los diccionarios  y los concatena los resultados de forma recursiva y por supuesto teniendo en cuenta los *. En el caso de encontrarse partes de la ER ya almacenados en los diccionarios copia sus tablas de transiciones. De no ser así los actualizará para que no vuelva a tener que calcularlas.

Actualiza diccionario de nombres ER con Natural. Cuando vuelva a tener que trabajar con un natural ya tiene toda la tabla de transiciones mínima calculada.

Inserta en ANDLTGlobal: estados [q0,q1,q2,q3,qn+2], estados finales [q2 (digito), qn+2 (natural)], símbolos {0,1,2,3,4,5,6,7,8,9}, donde desde q3 hasta qn+2 son copiados del AFDMínimo del natural respetando los índices de ANDLTGlobal y unidas mediante q0 a q3 con una transición Landa.

Reconocimiento de ER

A reconocer: 94

Estado: q0, Estados siguientes: q0,L a q1 y a q3, queda por reconocer: 94

Estado: q1, Estados siguientes: q1, 9 a q2, queda por reconocer 4.

Estado: q2 Final (digito), Estados siguientes: ninguno, queda por reconocer 4 No es digito.

Estado: q3, Estados siguientes: q3, 9 a q4, queda por reconocer 4.

Estado: q4, Estados siguientes: q5, 4 a qn, queda por reconocer nada.
Qn final (natural), es un natural.

Es una explicación sencilla aunque en realidad no trabaja de modo recursivo sino paralelamente con ayuda de Landa Clausura:

A reconocer: 94

(Q0),L ->  (q1,q3)
(q1,q3),9 -> (q2,q4)
(q2,q4),4 -> (qn) final donde qn es natural.

El programa en ejecución

ANDLT: 10 [save] #guardar
ANDLT: 21 [resetAll] #resetear
ANDLT: 26 [newER] #ER

Según va insertando ER muestra el número de estados del  ANDLTGlobal seguido del nombre de la ER entre corchetes y la ER.
Las que comienzan por # corresponden a comandos propios del programa.

ANDLT: 29 [digito] 0+1+2+3+4+5+6+7+8+9
ANDLT: 32 [natural] (digito)(digito)*

Las ya vistas en los ejemplos anteriores.

ANDLT: 36 [entero~positivo] (natural)+(@(natural))
ANDLT: 40 [entero~negativo] -(natural)
ANDLT: 44 [entero] (entero~positivo)+(entero~negativo)

Un entero positivo es un natural o +natural. Uso @ para no poner + ya que lo interpreta como una concatenación en lugar de un símbolo. De igual modo usa ~ para no insertar espacios en blanco en el nombre de una ER.

Un entero negativo es un natural precedido del símbolo –

Un entero puede ser un entero positivo o un entero negativo.

ANDLT: 52 [real~positivo] (entero~positivo)+((entero~positivo).)+(@.(natural))+(.(natural))+((entero~positivo).(natural))
ANDLT: 58 [real~negativo] (entero~negativo)+((entero~negativo).)+(-.(natural))+((entero~negativo).(natural))
ANDLT: 64 [real] (real~positivo)+(real~negativo)

Real positivo puede ser:

Entero positivo

Entero positivo.

+.natural

.natural

Entero positivo.natural

Lo mismo con los reales negativos.

ANDLT: 69 [fraccion~natural] (natural)/(natural)
ANDLT: 76 [fraccion~entera] (entero)/(entero)
ANDLT: 87 [fraccion~real] (real)/(real)
ANDLT: 98 [fraccion] (fraccion~natural)+(fraccion~entera)+(fraccion~real)
Todos los tipos de fracción posible.
ANDLT: 109 [número] (digito)+(natural)+(entero)+(real)+(fraccion)
ANDLT: 362 [digito~numeral~entero] ~+y+cero+ceros+un+uno+una+dos+tres+cuatro+cinco+seis+siete+ocho+nueve+diez+once+doce+trece+catorce+quince+dieciséis+diecisiete+dieciocho+diecinueve+veinte+veintiuno+veintiun+veintiuna+veintidós+veintitrés+veinticuatro+veinticinco+veintiséis+veintisiete+veintiocho+veintinueve+treinta+cuarenta+cincuenta+sesenta+setenta+ochenta+noventa+cien+ciento+cientos+doscientos+trescientos+cuatrocientos+quinientos+seiscientos+setecientos+ochocientos+novecientos+mil+millón+billón+trillón+millones+billones+trillones+más+menos
ANDLT: 583 [numeral~entero] (digito~numeral~entero)(digito~numeral~entero)*
ANDLT: 986 [numeral~real] (numeral~entero)~con~(numeral~entero)
ANDLT: 1390 [numeral~fraccion~EE] (numeral~entero)~entre~(numeral~entero)
ANDLT: 1998 [numeral~fraccion~ER] (numeral~entero)~entre~(numeral~real)
ANDLT: 2606 [numeral~fraccion~RE] (numeral~real)~entre~(numeral~entero)
ANDLT: 3418 [numeral~fraccion~RR] (numeral~real)~entre~(numeral~real)
ANDLT: 4637 [numeral~fraccion] (numeral~fraccion~EE)+(numeral~fraccion~ER)+(numeral~fraccion~RE)+(numeral~fraccion~RR)

Las ER para poder escribir los números de modo numeral.

ANDLT: 4640 [digito~romano] i+v+x+l+c+d+m+ł+¶
ANDLT: 4643 [numero~romano] (digito~romano)(digito~romano)*

Para interpretar los números romanos.

ANDLT: 4651 [digito~ordinal~forma~1] .º+.êr+.ª+.ôs+.âs
ANDLT: 4658 [ordinal~forma~1] (natural)(digito~ordinal~forma~1)
ANDLT: 4665 [digito~ordinal~forma~2] º+êr+ª+ôs+âs
ANDLT: 4671 [ordinal~forma~2] (natural)(digito~ordinal~forma~2)
ANDLT: 4683 [digito~ordinal~forma~3] er.+ro.+do.+to.+mo.+vo.+no.+ros.+dos.+tos.+mos.+vos.+nos.+ra.+da.+ta.+ma.+va.+na.+ras.+das.+tas.+mas.+vas.+nas.
ANDLT: 4691 [ordinal~forma~3] (natural)(digito~ordinal~forma~3)
ANDLT: 5038 [digito~ordinal~forma~4] ~+vigesimonona+vigesimonono+vigesimonovena+vigesimonoveno+vigesimoctavo+vigesimoctava+vigesimoséptimo+vigesimoséptima+vigesimosexto+vigesimosexta+vigesimoquinta+vigesimoquinto+vigesimocuarto+vigesimocuarta+vigesimotercero+vigesimotercera+vigesimosegundo+vigesimosegunda+vigesimoprimero+vigesimoprimera+decimonona+decimonono+decimonovena+decimonoveno+decimoctavo+decimoctava+decimoséptima+decimoséptimo+decimosexta+decimosexto+decimoquinta+decimoquinto+decimocuarto+decimocuarta+decimotercero+decimotercera+duodécimo+duodécima+decimosegundo+decimosegunda+undécimo+undécima+decimoprimero+decimoprimera+primero+primera+primer+segundo+segunda+tercero+tercera+tercer+cuarto+cuarta+quinto+quinta+sexta+sexto+sétimo+sétima+séptimo+séptima+octavo+octava+nono+nona+noveno+novena+décimo+décima+vigésimo+vigésima+trigésimo+trigésima+cuadragésimo+cuadragésimo+quincuagésimo+quincuagésima+sexagésimo+sexagésima+septuagésimo+septuagésima+octogésimo+octogésima+nonagésimo+nonagésima+duocentésimo+duocentésima+tricentésimo+tricentésima+cuadrigentésimo+cuadrigentésima+quingentésimo+quingentésima+sexcentésimo+sexcentésima+septingentésimo+septingentésima+octingentésimo+octingentésima+noningentésimo+noningentésima+centésimo+centésima+milésimo+milésima+millonésimo+millonésima
ANDLT: 5257 [ordinal~forma~4] (digito~ordinal~forma~4)(digito~ordinal~forma~4)*
ANDLT: 5480 [ordinal] (ordinal~forma~1)+(ordinal~forma~2)+(ordinal~forma~3)+(ordinal~forma~4)

Para trabajar con los ordinales.

Reconocimiento de 100

> 100
AFNDL: [entero, entero positivo, natural, número, real, real positivo]
  [Num. Nat.] '100'
  Valor Números Romanos: C
  Valor natural:         100
  Valor entero:          100
  Valor real:            100.0
  Valor numerador:       [Num. Ent.] '100'
  Valor denominador:     [Num. Ent.] '1'
  Valor Numeral:         cien

Reconocimiento de -89

> -89
AFNDL: [entero, entero negativo, número, real, real negativo]
  [Num. Ent.] '-89'
  Valor natural:         89
  Valor entero:          -89
  Valor real:            -89.0
  Valor numerador:       [Num. Ent.] '-89'
  Valor denominador:     [Num. Ent.] '1'
  Valor Numeral:         menos ochenta y nueve

Reconocimiento de 1002.3 y -124.14

> 1002.3
AFNDL: [número, real, real positivo]
  [Num. Real] '1002.3'
  Valor natural:         1002
  Valor entero:          1002
  Valor real:            1002.3
  Valor numerador:       [Num. Real] '1002.3'
  Valor denominador:     [Num. Real] '1.0'
  Valor Numeral:         mil dos con tres
> -124.14
AFNDL: [número, real, real negativo]
  [Num. Real] '-124.14'
  Valor natural:         124
  Valor entero:          -124
  Valor real:            -124.14
  Valor numerador:       [Num. Real] '-124.14'
  Valor denominador:     [Num. Real] '1.0'
  Valor Numeral:         menos ciento veinticuatro con catorce

Reconocimiento de 10/4

> 10/4
AFNDL: [fraccion, fraccion entera, fraccion natural, fraccion real, número]
  [Num. Fracc.] '10/4'
  Valor natural:         2
  Valor entero:          2
  Valor real:            2.5
  Valor numerador:       [Num. Ent.] '10'
  Valor denominador:     [Num. Ent.] '4'
  Valor Numeral:         diez entre cuatro

Reconocimiento de -10./.120

> -10./.120
AFNDL: [fraccion, fraccion real, número]
  [Num. Fracc.] '-10./.120'
  Valor natural:         83
  Valor entero:          -83
  Valor real:            -83.33333333333334
  Valor numerador:       [Num. Real] '-10.0'
  Valor denominador:     [Num. Real] '0.12'

Reconocimiento de diez mil con quinientos trece entre ocho con dos

> diez mil con quinientos trece entre ocho con dos
AFNDL: [numeral fraccion, numeral fraccion RR]
  [Num. Fracc.] '10000.513/8.2'
  Valor natural:         1219
  Valor entero:          1219
  Valor real:            1219.5747560975612
  Valor numerador:       [Num. Real] '10000.513'
  Valor denominador:     [Num. Real] '8.2'
  Valor Numeral:         diez mil con quinientos trece entre ocho con dos

Reconocimiento de 3er.

> 3er.
AFNDL: [ordinal, ordinal forma 3]
  Natural:  3
  Cifras 1: 3.º
  Cifras 2: 3º
  Cigras 3: 3ro.
  Orginal:  tercero
  Número:   Singular
  Género:   Masculino

Reconocimiento de cuarto

> cuarto
AFNDL: [digito ordinal forma 4, ordinal, ordinal forma 4]
  Natural:  4
  Cifras 1: 4.º
  Cifras 2: 4º
  Cigras 3: 4to.
  Orginal:  cuarto
  Número:   Singular
  Género:   Masculino

Reconocimiento de cmxiv

> cmxiv
AFNDL: [numero romano]
  [Num. Rom.] 'cmxiv'
  Valor Números Romanos: CMXIV
  Valor natural:         914
  Valor entero:          914
  Valor real:            914.0
  Valor numerador:       [Num. Nat.] '914'
  Valor denominador:     [Num. Nat.] '1'
  Valor Numeral:         novecientos catorce