410 likes | 514 Views
DESK. Patrones de Iteración (Iteration Patterns). Noviembre, Diciembre - 2002. El Problema. ¿Cómo lograr una transformación correcta entre widgets, de forma que está sea inferida automáticamente por DESK? Ejemplo: Transformación Lista => Tabla
E N D
DESK. Patrones de Iteración(Iteration Patterns) Noviembre, Diciembre - 2002
El Problema • ¿Cómo lograr una transformación correcta entre widgets, de forma que está sea inferida automáticamente por DESK? • Ejemplo: Transformación Lista => Tabla • El usuario copia y pega elementos de la Lista a la Tabla (usando por ejemplo las ventanas copy-paste) DESK infiere lo que el usuario pretende hacer y después de realizar un seguimiento, el sistema propone al usuario el realizar automáticamente la transformación completa. • ¿Cómo detectar en qué celdas de la tabla deben de ir la secuencia de elementos provenientes de la lista? • Movimiento lineal por las columnas (en la misma columna) • Movimiento lineal por filas (en la misma fila) • O quizás ambos movimientos a la vez
Solución • Detectar Patrones de Iteración • Detectar patrones en el Modelo de Monitorización que permitan inferir iteraciones en la copia de elementos de un widget a otro, detectando además lo que se copia, a dónde se copia y la relación entre la fuente y el destino • Los Patrones de Iteración podrían detectarse automáticamente, de forma general, o quizás venir predefinidos para detectar ciertos tipos de iteración que puedan darse entre widgets conocidos • Lista => Tabla, Árbol => Tabla, ComboBox => Tabla ... • Las transformaciones inversas (Tabla=>Lista, etc.) no deberían ser demasiado problemáticas (debido al carácter lineal de estos widgets), excepto para algunos casos más especiales (por ejemplo Árboles).
Modelización de Patrones • ¿Cómo detectarlos? • Creación de un Modelo de Widget (Para tablas, por ejemplo [Hurst, Cohen]) que permita modelizar: • Geometría del widget (layout, profundidad) • Elementos (número, columnas, filas, alineamiento (vertical, horizontal), tipo de dato almacenado (número, cadena, imagen, link...), y su tamaño [Hsin-Hsi] • En DESK, además podemos aportar información de alto nivel proveniente de los meta-datos embebidos en el HTML. Esto puede resultar útil para obtener información más detallada que distinga inequívocamente el widget y su relación con otros generados a partir de objetos de la red semántica.
Modelización de Patrones (y II) • En [Cohen] • Se crea un modelo abstracto usando DOM. Una tabla se modeliza como una cuadrícula, siendo las celdas un conjunto de rectángulos contiguos con coordenadas propias y con una representación explícita del contenido de cada celda. Las tablas anidadas son consideradas como sub-celdas dentro de celdas. • Cada tabla en el sistema es anotada (utilizando DOM) con meta-información, indicando: • Si es ó no una tabla de datos • Cada celda, su posición dentro del modelo de la tabla • Cada fila, si contiene información “cut-in” o no • Se usa un lenguaje Ltagpath para acceder o discriminar posiciones dentro de la tabla • (table,tr(cutIn=“no”),td(colRange=“2-2”)
“Reconocimiento” de Patrones • En DESK partimos siempre de un Modelo Estructurado de las acciones del usuario sobre los widgets que manipula, igualmente queda guardada información sobre el propio widget (modelización implícita) • ¿Cómo reconocer estos patrones para que DESK infiera el cambio por sí mismo en un proceso iterativo (patrones de iteración)? • Utilizar Modelos Probabilísticos (Bayes) • Utilizando Machine-Learning • Algoritmos de reconocimiento de patrones y redes neuronales • Para algunos casos, pueden servir redes neuronales lineales sencillas (reconocimiento de patrones de iteración entre celdas de una tabla) • Se necesita un conjunto de entrenamiento • Aunque la red se puede explotar con el conjunto ya aprendido • Solución clásica muy utilizada en wrappers
“Reconocimiento” de Patrones (y II) • Utilizando casos predefinidos de matching sobre widgets conocidos • Estos casos podrían expresarse utilizando un lenguaje de definición de alto nivel, basado quizás en expresiones algebraicas que representen la variación de características sobre las variables del modelo del widget en un proceso iterativo. • Como el utilizado para la extracción de información en entornos de wrappers (HyQL[Bauer] o Ltagpath [Cohen]) • La diferencia es que, bajo DESK, se posee un modelo estructurado, y la información que “interesa” ya ha sido extraída previamente, dando como lugar el Modelo de Monitorización, sobre el que habría que aplicar, realmente, el lenguaje de “extracción” de Patrones de Iteración
Patrones de Iteración bajo DESK • Bajo este punto de vista, podemos basarnos en la idea del “Agente de Información” [Bauer] para extraer información relevante sobre posibles Patrones de Iteración, presentes en el Modelo de Monitorización de DESK. • De esta forma se podrá inferir el poder proporcionar al usuario la opción de que DESK realice cambios o transformaciones entre widgets de forma automática. • Se puede utilizar la idea, ya concebida hace tiempo, sobre un “Agente de Inferencia” para detectar cambios entre widgets, cuya configuración puede suponer el definir el lenguaje de localización de Patrones de Iteración comentado anteriormente • Este agente también podría detectar cualquier cambio que implique un proceso iterativo, o buscar patrones de iteración en otros contextos/elementos en la edición • Reordenación de Listas • Cambiar y generalizar atributos de una celda a las demás, en una tabla • Etc.
Lenguaje de Definición • En nuestro caso serían reglas de actuación tras la activación del Agente • Configuración del Agente • Ejemplo: Transformación Lista => Tabla <TransformationHint searchLength=“100”> ... <widget type="List" changeTo="Table"> <Condition action="Creation" widget="Table" /> <Condition action=”PasteFragment" from="Table" to="List" repeat=“3” /> <Iteration_Pattern procedure=“IP_for_Tables” /> </widget> ... </TransformationHint>
Algoritmo del Agente • El agente se activa ante la aparición de ciertas acciones en el Modelo de Monitorización (como la copia de elementos entre widgets), a partir de ahí el agente utiliza la información de configuración <TransformationHint> para activar heurísticas más complejas en la transformación de widgets. Para ello es necesario satisfacer algunas condiciones previas, las cuales definen el futuro comportamiento de DESK para llevar a cabo correctamente la transformación de forma automática. • En las transformación, habría que contemplar el crear nuevas celdas de la tabla si el número de elementos de la lista supera al número de filas/columnas de la tabla • DESK podría realizar la inferencia ajustándose a la geometría de la tabla predefinida inicialmente por el usuario, dependiendo del patrón de iteración • Se podría preguntar al usuario, mediante un checkbox en la ventana de petición de la confirmación del cambio, el alterar o no la geometría • Se podría pedir el crear filas y columnas por separado. Ajustando DESK la copia completa de elementos a las filas/columnas existentes en la tabla
Algoritmo del Agente (II) • Algoritmo • 1) Dormir hasta la aparición de una acción de copia de elementos entre widgets • 2) Buscar, en la configuración del agente, la información adecuada sobre la transformación, según los elementos relacionados en la copia de elementos • 3) Comprobar que las pre-condiciones se cumplen correctamente en un entorno de N (SearchLength) primitivas atrás, buscando en el Modelo de Monitorización • 4) Buscar patrones de iteración en el Modelo de Monitorización, utilizando las acciones realizadas por el usuario que han dado lugar a la activación del Agente. • 5) Preguntar al Usuario si se desea acometer automáticamente el cambio, si es así sustituir el widget antiguo por el nuevo generado
Matching con Patrones de Iteración • Modelizar los widget involucrados en la transformación, utilizando el Modelo de Monitorización, detectando las acciones llevadas a cabo “N” veces por el usuario ( “repeat” en TransformationHint) • Estas acciones se meterán en un conjunto A = {: Modelo de Monitorización} para extraer características comunes (de controlar esto ya se encarga la fase anterior (TransformationHint)) y no comunes en base a las N veces que el usuario ha interactuado con los widgets • A.getSize(Widget) • A.getElementIndexSequence (Widget) • A.getColumnSequence(Widget) • A.getRowSequence (Widget) • A.getAverageColumnVariation(Widget) • A.getAverageRowVariation(Widget) • A.getID(Widget) • A.getClassName(Widget) • A.getObjectName(Widget) • A.getRelationName(Widget) • A.getElementAt(Widget,i[,j]) • A.getExistsRelation(Widget1,Widget2) • ...
Algoritmo “IP_for_Tables” A = {Primitives that reached TransformationHint(Repeat times)} W1 = List W2 = Table Input Values ColumnSequence = A.getColumnSequence(W2); RowSequence = A.getRowSequence (W2); ElemIndexSequence = A.getElementIndexSequence (W1); col_variation_factor = Average (ColumnSequence) row_variation_factor = Average (RowSequence); list_variation_factor = Average (ElemIndexSequence); i = ColumnSequence.getFirst(); j = RowSequence.getFirst(); k = ElemIndexSequence.getFirst(); While (W1.getSize()>k) { W2.setElementAt(i,j,List.getElementAt(k)); i = i + col_variation_factor; j = j + row_variation_factor; k = k + list_variation_factor; }
Algoritmos IP • En un principio los algoritmos IP (Iteration Patterns) son suficientemente generales • Pueden ser aplicados a distintos widgets que se introducen como parámetro en su llamada (XML) • El algoritmo IP_for_tables se puede utilizar para cualquier transformación entre un widget lineal (Lista, ComboBox), los cuales no ofrecen demasiada complejidad, y una Tabla. • Las tablas anidadas pueden ser modelizadas como sub-celdas dentro de celdas, para mayor comodidad, o incluir/definir un nuevo parámetro de variación en la iteración (nivel de profundidad en la tabla) • Se podría diseñar otro algoritmo más complejo para árboles. • El tratamiento de widgets lineales sería más general y menos complejo en la detección de patrones en la iteración
Función Average • Valor entero-redondedado de la media de las diferencias entre valores. • Se podría utilizar una media más robusta, para eliminar picos, detectándolos previamente • Este valor nos permitirá averiguar el incremento en la iteración, para movernos por las celdas de la tabla en función de los valores (x1,x2,...,xn) extraídos de las acciones monitorizadas al usuario
Ejemplos (I) • Variaciones discretas (filas) List 1 2 3 4 5 n X1 1 X2 2 X3 3 ColumnSequence = {1,1,1} RowSequence = {1,2,3} ElemIndexSequence = {1,2,3} col_variation_factor = 0 row_variation_factor = 1 list_variation_factor = 1 Table[1,1] = List[1] Table[1,2] = List[2] Table[1,3] = List[3] ... .... n Table
Ejemplos (II) • Variaciones discretas (filas+columnas+elementos) List 1 2 3 4 5 n X1 1 X3 2 X5 3 ColumnSequence = {1,2,3} RowSequence = {1,2,3} ElemIndexSequence = {1,3,5} col_variation_factor = 1 row_variation_factor = 1 list_variation_factor = 2 Table[1,1] = List[1] Table[2,2] = List[3] Table[3,3] = List[5] ... .... n Table
Ejemplos (III) • Robustez ante errores de secuencia Table List 1 2 3 4 5 n X1 1 2 X2 3 ColumnSequence = {1,1,1,1} RowSequence = {1,3,5,6} ElemIndexSequence = {1,2,3,4} col_variation_factor = 0 row_variation_factor = 2 (1.6) list_variation_factor = 1 Table[1,1] = List[1] Table[1,3] = List[2] Table[1,5] = List[3] Table[1,7] = List[4] ... 4 X3 5 X4 .... n
Problema => Patrones no Lineales • El cálculo medio del incremento puede corregir (en media) algunos errores, pero ¿qué sucede si realmente el usuario desea patrones iterativos como los siguientes? • En estos patrones es imposible inferir la iteración completa, debido a las indentaciones, es imposible saber dónde irá el próximo ítem (X) a partir de un elemento o coordenada inicial. X X X X X Aquí el incremento medio no es útil. Puede no existir una relación lineal directa entre las filas/columnas, además los ítems del widget “source” puede que tampoco se copien siguiendo un patrón iterativo “lineal” X X X X X X X X X X X X X .... X X .... X X X X X X X X X X X X X X X X X .... X X ....
Patrones no Lineales • La solución al problema no es obvia, la no-lineabilidad no puede ser tratada con algoritmos como los anteriores • Posibles soluciones • Modelos Probabilísticos • Machine Learning • Reconocimiento de Patrones • Redes Neuronales • En cualquier caso es difícil obtener un conjunto de entrenamiento o de hipótesis, debido a la infinidad de combinaciones a la hora de idear un patrón de iteración de este tipo (inserción en tablas) • En cualquier caso, habría que plantearse si estos patrones tienen sentido ó no • Quizás no sean demasiado “prácticos”, utilizados o comunes • Quizás no merezca la pena el tenerlos en cuenta a la hora de realizar una automatización del proceso (relación coste/resultado)
Posible Solución • Aprovechar ideas de Machine-Learning y Modelos Probabilísticos para emplear conocimiento previo existente en el reconocimiento de ciertos patrones • La idea sería tener un “pool” con una serie de patrones predefinidos, quizás los más utilizados o representativos, pudiendo ser ampliado por el usuario. Los patrones del usuario detectados durante la edición serán comparados con los del “pool” (Pattern Matching), pudiendo completar así la secuencia iterativa en caso de semejanza.
Pattern Matching • De esta forma se podrían detectar semejanzas en el pool, con los patrones predefinidos, para completar la secuencia • Patrones no lineales • O, en caso de que el “matching” no haya tenido éxito, ver si es posible inferir la secuencia iterativa • Patrones lineales
Pattern Matching (y II) • El Algoritmo podría ser el siguiente: Activación del Agente Si se cumplen las Pre-Condiciones { Aplicar Pattern Matching utilizando el Pool, Para detectar posibles Patrones de Iteración No Lineales Si (No se ha encontrado coincidencia con ningún patrón del pool) { Utilizar Algoritmo Para Patrones de Iteración Lineales } Si la inferencia tiene éxito { Avisar al usuario para completar la secuencia, y actuar según la elección del usuario } }
Modelización de Patrones (I) • Empleando una notación más intuitiva • Permite especificar casos de patrones ad-hoc, más complejos, definidos por el usuario • La secuencia debe estar completamente especificada <Pattern col_sequence=“1,1,2,2” row_sequence=“1,2,2,3” elm_sequence=“1,2,3,4”> <Resolve next_col_sequence=“3,3,4,4,...” next_row_sequence=“3,4,4,5,...” next_elm_sequence=“5,6,7,8,...” /> </Pattern> X1 X2 X3 X4 .... <Pattern col_sequence=“1,2,3,2,3,4” row_sequence=“1,1,1,2,2,2” elm_sequence=“1,2,3,4,5,6”> <Resolve next_col_sequence=“3,4,5,4,5,6,...” next_row_sequence=“3,3,3,4,4,4,...” next_elm_sequence=“7,8,9,10,11,...” /> </Pattern> X1 X2 X3 X4 X5 X6 .... <Pattern col_sequence=“1,2,1,2” row_sequence=“1,1,2,2” elm_sequence=“1,2,3,4”> <Resolve next_col_sequence=“3,4,3,4,5,6,...” next_row_sequence=“3,3,4,4,5,5,...” next_elm_sequence=“5,6,7,8,9,10,...” /> </Pattern> X1 X2 X3 X4 ....
Modelización de Patrones (y II) • Empleando una notación más abstracta • La secuencia no tiene por qué estar completamente especificada • Se aplicará inducción <Pattern col_sequence=“1,1,2,2” row_sequence=“1,2,2,3” elm_sequence=“1,2,3,4”> <Resolve i=“from 1 to List.getSize; i++1” next_col_sequence=“col[i], col[i]” next_row_sequence=“row[i], row[i+1]” next_elm_sequence=“elm[i]” /> </Pattern> X1 X2 X3 X4 .... <Pattern col_sequence=“1,2,3,2,3,4” row_sequence=“1,1,1,2,2,2” elm_sequence=“1,2,3,4,5,6”> <Resolve i=“from 1 to List.getSize; i++1” next_col_sequence=“col[i], col[i+1], col[i+1]” next_row_sequence=“row[i], row[i], row[i]” next_elm_sequence=“elm[i]” /> </Pattern> X1 X2 X3 X4 X5 X6 .... <Pattern col_sequence=“1,2,1,2” row_sequence=“1,1,2,2” elm_sequence=“1,2,3,4”> <Resolve i=“from 1 to List.getSize; i++2” next_col_sequence=“col[i], col[i+1], col[i], col[i+1]” next_row_sequence=“row[i], row[i], row[i+1], row[i+1]” next_elm_sequence=“elm[i]”/> </Pattern> X1 X2 X3 X4 ....
Definición de un “Pool” de patrones Se podrían incluir ambas notaciones, utilizando el lenguaje de configuración del Agente, e interpretando éste la información en cada caso. La configuración del Agente se podría construir mediante una herramienta de autor interactiva, donde el usuario describa directamente las secuencias de iteración interactuando con una tabla-modelo. <TransformationHint searchLength=“100”> ... <widget type="List" changeTo="Table"> <Condition action="Creation" widget="Table" /> <Condition action=”PasteFragment" from="Table" to="List" repeat=“4” /> <Lineal_Iteration_Pattern procedure=“IP_for_Tables” /> <Non_Lineal_Pattern_Pool> <Pattern col_sequence=“1,1,2,2” row_sequence=“1,2,2,3” elem_sequence=“1,2,3,4”> <Resolve i=“from 1 to List.getSize()” next_col_sequence=“col[i], col[i]” next_row_sequence=“row[i], row[i+1]” next_elm_sequence=“elm[i]” /> </Pattern> <Pattern col_sequence=“1,2,3,2,3,4” row_sequence=“1,1,1,2,2,2” elem_sequence=“1,2,3,4,5,6”> <Resolve next_col_sequence=“3,4,5,4,5,6,...” next_row_sequence=“3,3,3,4,4,4,...” next_elm_sequence=“7,8,9,10,11...” /> </Pattern> ... </Non_Lineal_Pattern_Pool> </widget> ... </TransformationHint>
Problema • ¿Cómo de grande debería de ser repeat? • No debería ser demasiado pequeño • Para evitar ambigüedades entre los Patrones de Iteración del “pool” que tengan características muy similares • Tampoco debería ser demasiado grande • Esto complicaría los algoritmos de detección de Patrones de Iteración lineales • Como por ejemplo en este caso. ¿Cómo deberían de tratarse este tipo de patrones? X X X X X X X X X ....
Solución • Detectar los saltos de fila • Pasos a seguir • Construir un conjunto RowJumpSet que almacene dónde se encuentran los saltos de fila dentro de RowSequence • Parametrizar el algoritmo Average para que pueda actuar por intervalos • De esta forma se podrán calcular los incrementos de celdas parciales por saltos • col_variation_factor (1,3) = Average (1,3,5) • row_variation_factor (1,3) = Average (1,1,1) • Generar dos nuevos conjuntos RowShiftSet y ColShiftSet, a partir de los Average parciales. Ejemplo: • ColShiftSet = {2,#,2} • RowShiftSet = {0,1,0} • Estos conjuntos permitirán saber el incremento por columnas hasta el salto (#) que se corresponde con el incremento de fila (1) • Se obtendrá un ciclo, actuando de la misma forma para cada fila/columna de la tabla hasta llegar a los límites geométricos de la misma, definidos por el usuario, o hasta que se acaben los elementos del widget “source” • Ahora el tamaño de repeat es más o menos indiferente • De esta forma se detectarían un mayor número de patrones lineales de iteración
Solución (II) ColumnSequence = {1,2,3,4,5,6,1,2,4,5} RowSequence = {1,1,1,1,1,1,2,2,2,2} RowJumpSet={7} col_variation_factor(1,6) = 1 col_variation_factor(7,N) = 1 (1.3) row_variation_factor(1,6) = 0 row_variation_factor(6,7) = 1 row_variation_factor(7,N) = 0 ColShiftSet = {1,#,1} RowShiftSet = {0,1,0} X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 .... ColunmSequence = {1,3,5,1,2,3,4,5,6,1,3,5} RowSequence = {1,1,1,2,2,2,2,2,2,3,3,3} RowJumpSet = {4,10} col_variation_factor(1,3) = 2 col_variation_factor(4,9) = 1 col_variation_factor(10,N) = 2 row_variation_factor(1,3) = 0 row_variation_factor(3,4) = 1 row_variation_factor(4,9) = 0 row_variation_factor(9,10) = 1 row_variation_factor(10,N) = 0 ColShiftSet = {2,#,1,#,2} RowShiftSet = {0,1,0,1,0} X2 X1 X3 X5 X7 X4 X6 X8 X9 X10 X11 X12 ....
Solución (III) ColunmSequence = {2,4,6,2,4,6} RowSequence = {1,1,1,3,3,3} RowJumpSet = {4} col_variation_factor(1,3) = 2 col_variation_factor(4,N) = 2 row_variation_factor(1,3) = 0 row_variation_factor(3,4) = 2 row_variation_factor(4,N) = 0 ColShiftSet = {2,#,2} RowShiftSet = {0,2,0} X1 X2 X3 X4 X5 X6 .... Los casos donde repeat es pequeño pueden seguir siendo detectados. Aquí el el cambio de filas/columnas lo decide el usuario. ColunmSequence = {1,2,4} RowSequence = {1,1,1} RowJumpSet = {} col_variation_factor(1,N) = 2 row_variation_factor(1,N) = 0 ColShiftSet = {2} RowShiftSet = {0} X1 X3 X2 ....
Solución (IV) • Para este otro tipo de patrones • Se tendrá en cuenta que si el “Shift” para filas es del tipo {0,i,0,i,...} y/o {0,#,0,#,...} para columnas, se calcularán de nuevo los conjuntos “Shift” desde 1 hasta N • Esto permitirá detectar también patrones de iteración con relaciones lineales directas entre filas y columnas ColunmSequence = {1,2,3} RowSequence = {1,2,3} RowJumpSet = {2,3} col_variation_factor(1,1) = 0 col_variation_factor(2,2) = 0 col_variation_factor(3,N) = 0 row_variation_factor(1,1) = 0 row_variation_factor(1,2) = 1 row_variation_factor(2,2) = 0 row_variation_factor(2,3) = 1 row_variation_factor(3,N) = 0 ColShiftSet = {0,#,0,#,0} RowShiftSet = {0,1,0,1,0} col_variation_factor(1,N) = 1 row_variation_factor(1,N) = 1 ColShiftSet = {1} RowShiftSet = {1} X1 X2 X3 ....
Solución (y V) ColunmSequence = {1,2,3} RowSequence = {1,2,3} RowJumpSet = {2,3} col_variation_factor(1,N) = 1 row_variation_factor(1,N) = 1 ColShiftSet = {1} RowShiftSet = {1} X1 X2 X3 .... ColunmSequence = {1,1,1} RowSequence = {1,2,3} RowJumpSet = {2,3} col_variation_factor(1,N) = 0 row_variation_factor(1,N) = 1 ColShiftSet = {0} RowShiftSet = {1} X1 X2 X3 .... ColunmSequence = {1,1,1,1} RowSequence = {1,2,3,5} RowJumpSet = {2,3,4} col_variation_factor(1,N) = 0 row_variation_factor(1,N) = 1 (1.3) ColShiftSet = {0} RowShiftSet = {1} X1 X2 X3 X4 ....
Algoritmo IP_for_Tables Mejorado A = {Primitives that reached TransformationHint(Repeat times)} W1 = List W2 = Table TG = User’s Selected Table Growth Input Values ColumnSequence = A.getColumnSequence(W2); RowSequence = A.getRowSequence (W2); ElemIndexSequence = A.getElementIndexSequence (W1); RowJumpSet = RowSequence.getRowJumpSet(); ColShiftSet = BuildColShiftSet(ColumnSequence, RowJumpSet); RowShiftSet = BuildRowShiftSet(RowSequence, RowJumpSet); Iterator = BuildIterator(W2.getBounds(), TG, ColShiftSet, RowShiftSet, ElemIndexSequence); ... While (Iterator.hasNext()) { i = Iterator.getNexti(i); j = Iterator.getNextj(j); k = Iterator.getNextk(k); W2.setElementAt(i,j,W1.getElementAt(k)); }
Problema • Los enfoques anteriores están, en cierta forma, orientados al tratamiento por filas, con saltos de columna fijos • ¿Cómo se podrían detectar patrones de este tipo? • Sería necesario, igualmente, el controlar que el usuario quiera realizar saltos de columnas, para tabular datos, dejar columnas de corte, etc. X1 X5 X1 X2 X3 X4 X5 X2 X6 X6 X7 X8 X9 X10 X7 X3 X4 X8 .... ....
Solución • Crear un nuevo conjunto ColJumpSet, donde se codifiquen los saltos de columnas • De esta forma, se podría averiguar de antemano la dinámica de las inserciones: Si RowJumpSet > ColJumpSet => Inserción por Columnas (&) Si no => Inserción por Filas (#) Si RowJumpSet = ColJumpSet => Inserción lineal, los conjuntos “Shift” no son necesarios • Así, la construcción de los conjuntos “Shift” se hará por columnas (RowShiftSet(&)) o por filas (ColumnShiftSet(#)) • Es necesario partir siempre de una coordenada o elemento inicial, a partir del cual se empezará a iterar (origen(x,y)), y con el que se construirá un iterador cíclico que complete la iteración planteada
Ejemplo ColunmSequence = {2,4,6,2,4,6} RowSequence = {1,1,1,3,3,3} ColJumpSet = {2,3,4,5,6} RowJumpSet = {4} => Inserción por Filas col_variation_factor(1,2) = 2 col_variation_factor(2,3) = 2 col_variation_factor(4,5) = 2 col_variation_factor(5,6) = 2 row_variation_factor(1,2) = 0 row_variation_factor(2,3) = 0 row_variation_factor(3,4) = 2 row_variation_factor(4,5) = 0 row_variation_factor(5,6) = 0 ColShiftSet = {(Col:2),2,2,#,2,2} RowShiftSet = {(Row:1),0,0,2,0,0} X1 X2 X3 X4 X5 X6 .... Pos. Inicial {Col:2, Row:1} ColunmSequence = {2,2,4,4,6,6} RowSequence = {1,3,1,3,1,3} ColJumpSet = {3,5} => Inserción por Columnas RowJumpSet = {2,3,4,5,6} col_variation_factor(1,2) = 0 col_variation_factor(2,3) = 2 col_variation_factor(3,4) = 0 col_variation_factor(4,5) = 2 col_variation_factor(5,6) = 0 row_variation_factor(1,2) = 2 row_variation_factor(3,4) = 2 row_variation_factor(5,6) = 2 ColShiftSet = {(Col:2),0,2,0,2,0} RowShiftSet = {(Row:1),2,&,2,&,2} X1 X3 X5 X2 X4 X6 .... Pos. Inicial {Col:2, Row:1}
Ejemplos • Esta técnica también es útil para patrones con columnas de “cut-in” • Ahora el control de errores en inserciones no deseadas no tiene sentido, se actuará según la voluntad del usuario. ColunmSequence = {1,1,1,1,3,3,3,3} RowSequence = {1,2,3,4,1,2,3,4} ColJumpSet = {5} => Inserción por Columnas RowJumpSet = {2,3,4,5,6,7,8} ColShiftSet = {0,0,0,2,0,0,0} RowShiftSet = {1,1,1,&,1,1,1} X1 X5 X2 X6 X7 X3 X4 X8 .... ColunmSequence = {1,2,4,5,6,1,2,4,5,6} RowSequence = {1,1,1,1,1,2,2,2,2,2} ColJumpSet = {2,3,4,5,6,7,8,9,10} RowJumpSet = {6} => Inserción por Filas ColShiftSet = {1,2,1,1,#,1,2,1,1} RowShiftSet = {0,0,0,0,1,0,0,0,0} X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 ....
Ejemplos (II) • Esta solución seguiría siendo compatible con los casos “triviales” estudiados anteriormente • Aunque habría que controlar algunas condiciones, como que si alguno de los dos conjuntos “Jump” es vacío, se procederá a un cómputo normal (lineal) ColunmSequence = {1,3,5} RowSequence = {1,1,1} ColJumpSet = {2,3} RowJumpSet = {} => Inserción por Filas ColShiftSet = {2,2,[#]} = {2} RowShiftSet = {0,0} = {0} X1 X3 X2 .... ColunmSequence = {1,1,1} RowSequence = {1,2,3} ColJumpSet = {} => Inserción por Columnas RowJumpSet = {2,3} ColShiftSet = {0,0} = {0} RowShiftSet = {1,1,[&]} = {1} X1 X2 X3 ....
Ejemplos (y III) • La solución, en general, tiene la ventaja de poder “predecir” los saltos de columna y fila, dependiendo de la dinámica de la iteración (#, &). El resto de parámetros se siguen controlando según la dimensión original de la tabla y de la decisión del usuario con respecto al posible crecimiento de la Tabla ColunmSequence = {1,2,3} RowSequence = {1,2,3} ColJumpSet = {2,3} => Inserción por Filas RowJumpSet = {2,3} => Inserción por Columnas ColShiftSet = {1,#} = {1} RowShiftSet = {1,&} = {1} X1 X2 X3 .... ColunmSequence = {1,3,5,1,2,3,4,5,6,1,3,5} RowSequence = {1,1,1,2,2,2,2,2,2,3,3,3} ColJumpSet = {2,3,4,5,6,7,8,9,10,11,12} RowJumpSet = {4,10} => Inserción por Filas ColShiftSet = {2,2,#,1,1,1,1,1,#,2,2} RowShiftSet = {0,0,1,0,0,0,0,0,1,0,0} X2 X1 X3 X5 X7 X4 X6 X8 X9 X10 X11 X12 ....
Algoritmo IP_for_Tables Modificado A = {Primitives that reached TransformationHint(Repeat times)} W1 = List W2 = Table TG = User’s Selected Table Growth Input Values ColumnSequence = A.getColumnSequence(W2); RowSequence = A.getRowSequence (W2); ElemIndexSequence = A.getElementIndexSequence (W1); ColJumpSet = ColSequence.getColJumpSet(); RowJumpSet = RowSequence.getRowJumpSet(); ColShiftSet = BuildColShiftSet(ColumnSequence, ColJumpSet, RowJumpSet); RowShiftSet = BuildRowShiftSet(RowSequence, ColJumpSet, RowJumpSet); Iterator = BuildIterator(W2.getBounds(), TG, ColShiftSet, RowShiftSet, ElemIndexSequence); ... While (Iterator.hasNext()) { i = Iterator.getNexti(i); j = Iterator.getNextj(j); k = Iterator.getNextk(k); W2.setElementAt(i,j,W1.getElementAt(k)); }
Comentarios/Observaciones • Los “N” PasteFragment se van insertando en el Modelo de Monitorización, esto servirá para inferir todo el proceso de transformación. Pero cuando DESK efectúa el cambio completo, ¿no habría que sustituir esas “N” repeticiones (junto con la creación del nuevo widget a transformar) por la primitiva que refleja la transformación completa? • ¿Sería necesario el insertar los nuevos datos provenientes del widget “source” a partir del proceso de inferencia? • Quizás no haga falta, esto podría resolverse en DESK Server-Side.