En este punto se verán el orden de complejidad computacional del algoritmo y el orden de complejidad en cuanto a consumo de recursos en memoria si dicho algoritmo se implantase vías software ya que, aunque en un circuito hardware el tiempo se mida en ciclos, el consumo de memoria puede verse notablemente afectado por las posibles adaptaciones y limitaciones necesarias para su desarrollo en un circuito hardware. Se plantean, por tanto, las complejidades de los diferentes pasos del algoritmo planteado, que vistos de uno en uno quedan:
Dentro del cuerpo del bucle tenemos:
{2} – Teniendo en cuenta la definición de cota de máxima aplicabilidad presentada en el capítulo correspondiente a las bases teóricas del presente trabajo y cuyo significado es el del número de veces que podría aplicarse una regla sobre el multiconjunto de objetos actual, el método de cálculo de dicha cota no es más que establecer el mínimo de los valores obtenidos de la división de cada una de las multiplicidades de cada símbolo del multiconjunto entre la multiplicidad del objeto correspondiente en el antecedente de la regla (siempre que sea distinto de cero).
Si se denomina S al alfabeto utilizado, Oi a cada una de los símbolos de dicho alfabeto, W al multiconjunto de objetos de la región y r[i] a la multiplicidad del objeto i en el antecedente de la regla, tal y como establece [Fernández, 2011], el pseudocódigo para el cálculo en ejecución secuencial de la cota de máxima aplicabilidad de una regla se puede representar como:
{1}Max 0
{2}FOR EACH Oi IN |S|
{3} IF r[i] <> 0 THEN {4} aux W[i] / r[i]
{5}IF (aux < Max) or (Max = 0) THEN {6} Max aux
{7}END
197
Claramente, este pseudocódigo se corresponde con una ejecución secuencial para el cálculo de la mencionada cota. La complejidad de este algoritmo viene determinada por el bucle del paso {2} (el resto tienen complejidad O(1)), que se ejecuta tantas veces como elementos haya en el conjunto de símbolos y por tanto es O(|S|).
Dado que el objetivo perseguido es la de aumentar el nivel de paralelismo en la medida de lo posible, resulta interesante plantear la consecución de la cota de máxima aplicabilidad mediante un algoritmo de ejecución paralela. Esto es posible si se diseña de tal manera que las divisiones entre los objetos del multiconjunto y los correspondientes al antecedente de la regla se realizan todos en paralelo para proceder a una comparación posterior dos a dos ejecutándose también en paralelo por niveles.
3 1 2 1 0 2 3 2 6 8 2 5 9 8 9 5 antecedente multiconjunto a b c d e f g h a b c d e f g h 8/2 9/0 5/1 2/2 8/1 9/3 5/2 6/3 a b c d e f g h 2 8 1 5 9 4 3 2 a b c d e f g h 2 1 4 2 1 2 1 Divisiones en paralelo Nivel 1 Nivel 2 Nivel 3
Figura 5.6 Cálculo de la cota de máxima aplicabilidad por niveles
Como se puede observar en la figura del ejemplo (Figura 5.6), se ejecutan todas las divisiones en paralelo (en la versión para desarrollo software esto supondría un proceso para cada división) y los resultados se comparan dos a dos de tal manera que en el primer paso, si hay n símbolos inicialmente, se efectúan n/2 comparaciones, y reiterando las comparaciones con los resultados, se tiene que el número de pasos necesarios para obtener un único número es log2 n. En el ejemplo, con 8 símbolos en el antecedente, se efectúan solamente tres comparaciones entre los resultados.
Dado que la complejidad de la división es O(1), aplicar este método vendría determinado por el bucle necesario para efectuar log2 n comparaciones y por tanto tendríamos que el orden de complejidad computacional de este método sobre un multiconjunto S sería O(log2 |S|).
198
{3} – La complejidad de la generación del número aleatorio es O(1), ya que se generan todos en paralelo.
{4} – En paralelo:
{5} – La multiplicación de un número entero por un multiconjunto tiene complejidad O(|S|) si se efectúa de manera secuencial ya que se producen tantas multiplicaciones como elementos hay en el multiconjunto aunque es O(1) si se ejecutan de manera paralela.
{9} – La generación aleatoria tiene complejidad de orden O(1). {10} – En paralelo:
{11} – La substracción de dos multiconjuntos tiene complejidad O(|S|) si se efectúa de manera secuencial ya que se producen tantas restas como elementos hay en los multiconjuntos, aunque es O(1) si se ejecutan de manera paralela dichas restas.
{12} – El almacenaje tiene orden O(1) (Se suma ki al número de regla aplicada).
Tenemos pues que la complejidad computacional presentará variaciones dependiendo de la implantación que se haga de cara al resultado final. En caso de que la implantación de todos los diferentes pasos (no del algoritmo global) sea secuencial, la mayor complejidad obtenida será del orden O(|S|) mientras que si se pudiesen implantar todos los pasos para una ejecución en paralelo, la máxima complejidad sería la correspondiente al cálculo de la cota de máxima aplicabilidad, es decir O(log2 |S|).
Por otra parte, el consumo de recursos de memoria puede parecer que, a primera vista, no es excesivo ya que el manejo de los recursos se refiere al número de símbolos que hay en el multiconjunto. Sin embargo hay dos factores que afectan gravemente a esta complejidad:
a) Hay que recordar que hasta aquí se ha descrito la complejidad computacional del cálculo de determinados elementos para una regla, ya que se efectúan sobre todas ellas n paralelo. Ahora bien, como es natural, el proceso indicado se debe ejecutar sobre todas las reglas activas de la región y por tanto, el consumo de recursos en memoria se multiplica por el número de reglas existentes. Si para una regla en particular se necesitan recursos en memoria como:
- O(|S|) para el antecedente de la regla y O(|S|) para el multiconjunto de objetos.
- Los recursos extras necesarios para el cálculo de la cota de máxima aplicabilidad varían dependiendo del método implantado entre O|S| (secuencial) y O(|S|log2 |S|) (paralelo).
199
- O(|S|) para almacenar los resultados intermedios en el resto de los pasos.
Si se denominase R al conjunto de reglas activas inicial, la complejidad de los recursos en memoria se vería multiplicada por la cardinalidad del mismo: la complejidad en algunas operaciones vendrá dada por tanto, por O(|R|*|S|). b) El segundo factor a tener en cuenta y que vuelve a afectar gravemente a los recursos necesarios en memoria es el hecho de que, como se ha indicado, la intención es la de aumentar el intra-paralelismo a nivel interno de la membrana y que para ello se consideraría como conjunto de reglas activas al conjunto potencia del conjunto de reglas iniciales. Por ello, otra vez sin afectar a la complejidad en el cálculo computacional ya que se efectúa en paralelo, los recursos necesarios en memoria crecerán de manera exponencial con el número de reglas activas. El orden de complejidad será por tanto:
O(|P*(R)|*|S|) = O(2|R|*|S|)
ya que el cardinal del conjunto potencia es 2|R|.