[ALGEBRA DE MATRICES] Matriz triangular INFERIOR DESCENDIENTE en C.

Iniciado por dijsktra, 4 Mayo 2020, 22:24 PM

0 Miembros y 1 Visitante están viendo este tema.

dijsktra

Cita de: fary en  3 Mayo 2020, 20:21 PM
dijsktra deberías de poner mas retos como este  :P

Va por el fary !

Nuestros hermanos de América puede que no sepan quien es el Fary... Es... el "más cantante de España",,,   https://www.youtube.com/watch?v=XLZO3DGRrfY
(Parodia de lo mal que hablan los "gallegos"!!)

A vueltas con las matrices... Se trata ahora de comprobar si una matriz es triangular inferior descendiente...


Yo lo he hecho de arriba a bajo. Es similar, pero es como si a un zurdo le mandaran escribir con la derecha, o a un diestro con la izquierda...

Vale el mismo código base de

https://foro.elhacker.net/programacion_cc/algebra_de_matrices_matriz_triangular_superior_desdendiente_en_c-t504451.0.html;msg2220794#msg2220794

int lowerTriangleDesc(const int **A,
     const int N)
{
 // Start code here.
 return 1;
}


De nuevo, el que más simple/bonito lo hace, (no el que termine antes, como en los concursos) gana!

Ojo , YreX-DwX, no se te olivde que tienen que valer para matrices N>=1 columnas....

Ejemplos de entrada de casos son...
EN DOS DIAS PONGO LA SOLUCION

3
1 0 0
0 1 0
0 0 1
lowerTriangleDesc: 1
3
1 2 3
0 4 5
0 0 6
lowerTriangleDesc: 0
3
1 2 3
2 4 5
0 0 6
lowerTriangleDesc: 0
5
1 0 0 0 0
1 2 0 0 0
1 2 3 0 0
1 2 3 4 0
1 2 3 4 5
lowerTriangleDesc: 1
5
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
lowerTriangleDesc: 1
1
1
lowerTriangleDesc: 1
1
0
lowerTriangleDesc: 1


Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)

K-YreX

Hmm... Veo demasiada similitud con el otro tema. Esto me da que pensar si será tan simple o hay alguna otra forma escondida. Le he dado muchas vueltas a ver si encontraba una alternativa como ir reduciendo la matriz por recursividad, pero no es posible (o eso me ha parecido, tengo un poco olvidado el trabajo directo con memoria...) al no ser una matriz como tal contigua en memoria.

Así que aprovecharé para sacarme la espinita que se me quedó con el otro tema...
Cita de: dijsktra en  4 Mayo 2020, 22:24 PM
Ojo , YreX-DwX, no se te olivde que tienen que valer para matrices N>=1 columnas....
Y tranquilo, ya no me olvidaré de las matrices de orden 1 :xD :xD


int lowerTriangleDesc(const int **A, const int N){
    int i, j = N;
    for(i = 0; i < N-1 && j == N; ++i)
        for(j = i+1; j < N && !A[i][j]; ++j);
    return j == N;
}


PD: Sigo pensando que hay alguna solución oculta sorprendente. No dormiré tranquilo hasta ver la solución. :xD
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

dijsktra

Cita de: YreX-DwX en  5 Mayo 2020, 18:01 PM
Hmm... Veo demasiada similitud con el otro tema.

Tienes razon. YreX-DwX... No me ha quedado bien.... :-( :-( Era muy similar al otro.... Y la solucion que pones es implecable...

Cita de: YreX-DwX en  5 Mayo 2020, 18:01 PM

int lowerTriangleDesc(const int **A, const int N){
    int i, j = N;
    for(i = 0; i < N-1 && j == N; ++i)
        for(j = i+1; j < N && !A[i][j]; ++j);
    return j == N;
}


yo habia propuesto

int lowerTriangleDescBis(const int **A,
const int N)
{
  int i,j;
  for (i=N-1,j=N; i && (j==N); i-=(j==N))
    for(j=i; j<N && !A[i-1][j];j++);
  return !i;
}


Cita de: YreX-DwX en  5 Mayo 2020, 18:01 PM
PD: Sigo pensando que hay alguna solución oculta sorprendente. No dormiré tranquilo hasta ver la solución. :xD

  VAMOS A HACERLO DIFICIL, PERO DIFICILISMO !

Todo el mundo ve que hay dos bucles y dos variables

ESTE ES EL RETO:


PROGRAMAR LA SOLUCION USANDO SOLO UN BUCLE Y UNA SOLA VARIABLE DE CONTROL, A PARTE DE LAS QUE SE DAN POR PARAMETRO


(Por supuesto, el programa sera mas dificil de legible, pero sera igualmente correcto....)


No me pidais la solucion en un dia que no se si tendre tiempo... Se que se puede, y tengo que hacerla...
y tu, YreX-DwX, m'as vale que duermas un poco...que te puedes volver tarumba... :rolleyes: :rolleyes:


Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)

K-YreX

Cita de: dijsktra en  6 Mayo 2020, 00:03 AM
  VAMOS A HACERLO DIFICIL, PERO DIFICILISMO !

Todo el mundo ve que hay dos bucles y dos variables

ESTE ES EL RETO:

PROGRAMAR LA SOLUCION USANDO SOLO UN BUCLE Y UNA SOLA VARIABLE DE CONTROL, A PARTE DE LAS QUE SE DAN POR PARAMETRO

(Por supuesto, el programa sera mas dificil de legible, pero sera igualmente correcto....)

Esto sí que promete.  ;-) ;-)
Después de darle unas cuantas vueltas creo que está cerca pero no consigo sacarlo así que dejo mi razonamiento por si alguien se anima a seguir mientras yo duermo... (Espero no soñar con esto :rolleyes:)

La idea es tratarlo algo así como un array unidimensional, es decir, un único índice que se incrementa desde 1 hasta n siendo n el número de casillas a recorrer. Resulta que n = (N*(N-1)/2). Iremos incrementando el contador en 1 a no ser que una casilla no sea nula en cuyo caso podemos concluir que esa matriz no es triangular inferior.

i := 1
MIENTRAS i <= (N*(N-1)/2) and i != 0 ENTONCES
    i = (A[f(i)][g(i)] == 0) * (i+1)
FIN MIENTRAS
RETURN i

Como se puede apreciar falta definir las funciones f() y g() que determinen la fila y columna del siguiente elemento en función de i.

Parece sencillo usando los operadores de división entera y módulo pero no es tan simple. Probando con matrices de orden N >= 2 (ya que de orden 1 sería triangular sin entrar por el bucle) he encontrado lo siguiente:

N = 2 -> M = (N*(N-1)/2) = 1
i    -> 1
f(i) -> 0
g(i) -> 1

N = 3 -> M = 3
i    -> 1 - 2 - 3
f(i) -> 0 - 0 - 1
g(i) -> 1 - 2 - 2

N = 4 -> M = 6
i    -> 1 - 2 - 3 - 4 - 5 - 6
f(i) -> 0 - 0 - 0 - 1 - 1 - 2
g(i) -> 1 - 2 - 3 - 2 - 3 - 3

N = 5 -> M = 10
i    -> 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10
f(i) -> 0 - 0 - 0 - 0 - 1 - 1 - 1 - 2 - 2 - 3
g(i) -> 1 - 2 - 3 - 4 - 2 - 3 - 4 - 3 - 4 - 4

N = 6 -> M = 15
i    -> 01 - 02 - 03 - 04 - 05 - 06 - 07 - 08 - 09 - 10 - 11 - 12 - 13 - 14 - 15
f(i) -> 00 - 00 - 00 - 00 - 00 - 01 - 01 - 01 - 01 - 02 - 02 - 02 - 03 - 03 - 04
g(i) -> 01 - 02 - 03 - 04 - 05 - 02 - 03 - 04 - 05 - 03 - 04 - 05 - 04 - 05 - 05

Y así sucesivamente. Yo creo que se ve perfectamente el patrón. El problema como ya he dicho es sacar la que sería la fórmula cerrada de f() y g().
Si alguien se quiere animar a intentar seguir o a exponer su razonamiento... :rolleyes: :rolleyes:
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

fary

Hola, no había visto esto... ¿No es mejor crear otro tema para no mezclar todo?  ;-) ;-)

saludos!
Un byte a la izquierda.

Serapis

No es más complicado hacerlo en un solo bucle, tan solo es cuestión de precisar más cálculos (tampoco muchos más), que la simpleza de dos bucles ofrece...

(nota: Estoy tomando como ejemplo el triangulo de la otra ocasión ya que es trivial modificarlo a cualquiera de las esquinas.
Igualmente la nomenclatura de: (derecha izquierda, superior, inferior) no tiene más punto que ponerse de acuerdo. Personalmente entiendo que acomoda más denominarla conforme a la esquina que ocupa al vértice del triángulo que conecta solo con ceros, y que para el ejemplo a continuación es: inferior-iizquierda).

Para entender el mecanismo subyacente hay que estudiar un poquito la matriz.
...y  atribuir algunos estados que nos permitan dar flujo al cálculo

Matriz: 0-35 ceros saltos  index ini
5 6 0 8 2 3 - 0  - 6          00 - estado de escape
0 4 3 9 0 0 - 1  - 5          06
0 0 1 5 3 4 - 2  - 4          12
0 0 0 5 2 0 - 3  - 3          18
0 0 0 0 7 0 - 4  - 2          24
0 0 0 0 0 6 - 5  - 1          30 - estado inicial
x x x x x x                   xx - estados de cambio
                         ancho + 1: estado de avance


Explicando la tabla...
- Lo obvio es que los ceros aumentan en uno con cada fila... en la columna fila se ha puesto una columna que lleva dicha cuenta. Una funcion podría simplemente contar cuando son 0 y devolcerá TRUE cuando sea el sumatorio de dicha serie. Aunque claramente es más ineficiente que devolver false tan pronto un valor no cumple la restricción.
- La columna saltos, indica cuantos hay que omitir tras recorrer los 0. Algo tangible es que 'ceros + saltos = ancho, pués por algo son los elementos en una fila.
- He añadido una última columna que señala los índices (de un array unidimensional) que suponen el primer elemento de cada fila.

En el algoritmo a continuación se empieza por el vértice que da nombre al triángulo (ver nota arriba), y recorre en diagonal (en el ejemplo) hacia abajo y a la derecha... Así he añadido algunos estados para terminar de entender...
El estado inicial es pués 30 : index = (size- ancho)
En cada ciclo aumentará: index += (ancho +1)
Cuando se alcanza un valor de index en los 'estados de cambio', justamente el enésimo valor que ocupa en esa fila (fuera de la matriz), es lo mismo que señalar la fila siguiente a la que saltar (pués es simétrico, considerando justamente como vértice del triángulo la esquina antedicha en la nota superior).
El bucle termina cuando alcanza el estado de escape, que para este triángulo será el índice 0.

...y ahora el pseudocódigo (que cualquiera puede traducir a cualquier lenguaje, ya que el problema no es un problema restrictivo a ningún lenguaje específico, es decir no es un problema de ningún lenguaje si no de algoritmia)...

Buleano = Funcion EsMTID(array byte Valores(), entero Ancho, entero Size)
    entero index
   
    index = (Size - Ancho)
    Hacer
        Si (Valores(index) <> 0) Devolver False  // *
        index = (index + Ancho + 1)
       
        Si (index > Size)      // conocemos la fila a la que saltar por el sobrante: (Index Modulo Ancho)
            index = (Size - (Ancho * (1 + (index Modulo Ancho))))
        fin si
    Repetir Mientras  (index > 0)
   
    Devolver True
Fin Funcion

* Sí, también reconoce correctamente el caso de una matriz de 1x1

dijsktra

#6
Cita de: NEBIRE en  6 Mayo 2020, 18:22 PM
...y ahora el pseudocódigo (que cualquiera puede traducir a cualquier lenguaje, ya que el problema no es un problema restrictivo a ningún lenguaje específico, es decir no es un problema de ningún lenguaje si no de algoritmia)...

Tengo que dejar claro que su idea es la que más me ha gustado.
Comentarios...

  • Mete  una variable mas, size, que no es m'as que ancho*ancho, luego se puede enmendar
  • No es programacion estructurada (return 0) pero eso es facilmente enmendable.Ojo!, no digo que no sea válida en C, digo que no es C-estructurada
  • La construccion "repeat until", no es la adecuada. De hecho para N=1, el algoritmo falla. Pero es facilmente enmendable

Con las ligeras enmiendas... El pseudocodigo de NEBIRE pasado a C, resulta

int upperTriangleDesc(const int *A, const int N)
{
 int i=N*N-N;
 while (i && !A[i])
   {
     i += N + 1;
     if (i > N*N)
i = N*N - (N*(1 + (i%N)));
   }
 return !i;
}

Y algunos resultados (correctos, por supuesto)
1
1
upperTriangleDesc: 1
2
1 1
0 1
upperTriangleDesc: 1
3
1 2 3
0 1 2
0 0 1
upperTriangleDesc: 1
3
1 2 3
0 1 2
1 0 1
upperTriangleDesc: 0

Es encomiable el esfuerzo por hallar la ley que aplica al indice "i". Realmente es una función compleja...

Sin embargo... Hay un detalle no menor que puede echarse al traste....

SE HA CAMBIADO EL TIPO DE LA MATRIZ DE BIDIMENSIONAL A UNIDIMENSIONAL


const int **A;
// Set by
if  ((A=(int**)malloc(N*sizeof(int *)))==NULL)
 {
   perror("malloc");
   exit(1);
 }
for(int n=0;n<N;n++)
 {
   if  ((A[n]=(int*)malloc(N*sizeof(int)))==NULL)
     {
perror("malloc");
exit(1);
     }
 }

por
const int *A;

if  ((A=(int*)malloc(N*N*sizeof(int)))==NULL)
 {
   perror("malloc");
   exit(1);
 }


EDIT
Esto supone que se han cambiado las condiciones del problema original por otro que era equivalente, que lo emula ,pero con condiciones distintas (los datos de entrada se presuponen codificados de otro modo). As'i, con N=6, el resultado no es correcto cuando se le pasa un valor const int **A, malloc(N), ya que A[30] , esta fuera de memoria. (si lo esta const int *A, malloc(N*N)...)

Todavia no tengo la mia... tengo algnuas cosas todavía sin madurar.
Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)

dijsktra

#7
Bueno, ya va siendo hora que vaya dando una respuesta a este tema... ME VA A QUEDAR UN MENSAJE LARGO, pero a lo mejor a la posteridad le sirve de ayuda.
Recordemos que las condiciones para resolverlo eran

  • sin cambiar la codificacion de los parametros, esto es, entra const int **A, no const int *A
  • una sola variable de control, n, (aparte de los parametros, A, N)
  • Un solo bucle. No he podido, me he cansado!! (Se puede, no obstante)

Cita de: YreX-DwX en  6 Mayo 2020, 05:43 AM

i := 1
MIENTRAS i <= (N*(N-1)/2) and i != 0 ENTONCES
   i = (A[f(i)][g(i)] == 0) * (i+1)
FIN MIENTRAS
RETURN i

Como se puede apreciar falta definir las funciones f() y g() que determinen la fila y columna del siguiente elemento en función de i.Si alguien se quiere animar a intentar seguir o a exponer su razonamiento... :rolleyes: :rolleyes:

Ni mucho menos es tan simple. En https://en.wikipedia.org/wiki/Pairing_function y en http://szudzik.com/ElegantPairing.pdf se describen algunos esquemas de recorrido de una matriz, proyectando dos dimensiones en uno y viceversa. No viene la tuya, pero para otras mas sencillas quedan expresiones muy complejas que trascienden el uso basico de % y /.... Un horror, vamos porque nosotros queremos no pasar de % y /.

Yo sabia que se podía, porque un resultado clásico de computabilidad dice:

Citartodo lo que se puede computar con programa estilo "while" y N variables se puede hacer con 1 variable.

La contrapartida será, por supuesto,


  • la legibilidad, No tiene interes pr'actico, pero si t'eorico, pues se puede hacer lo mismo con una variable que con N, (tesis de turing-Church)
  • la eficiencia.Los programas consumen más tiempo de ejecución, aunque sin dejar de ser tratable polinomialmente (Tesis de Cook)  
Esta  es la estretegia:


En una variable se pueden codificar el estado de N variables, sin más que adoptar en esa variable el producto de los primeros N numeros primos elevados al valor de cada variable respectiva.


Eso quiere decir que para codificar


x,y = 3, 1


Damos el valor a n de.

n = (2^3)*(3^1)=8*3=24


Que por el teorema de la Aritmetica, denota univocamente unico numero o valor para n. La forma para recuperar x, (y) será el  exponente de la mayor potencia de 2, (3) que todavia haga divisible a n entre ella.


x = max { k | \exists z n=2^k*z } = 3, ya que 2^4=32 no divide a 24
y = max { k | \exists z n=3^k*z } = 1 ya que 3^2=9 no divide a 24


Pero recordemos que no podemos usar m'as que una variable, luego es ilegal llamar a funciones f(n) g(n), porque estas har'ian uso de pilas y variables, y eso es trampa... Da la casualidad de que esas funciones SI SE PUEDEN COMPUTAR SOLO CON % Y /.

Este es el codigo que quier implementar de partida.

int lowerTriangleDesc(const int **A, const int N)
{
 int i, j ;
 for(i = 0, j=i+1; i < N-1 && !A[i][j]; )
   if (j==N-1) { i++; j = i + 1 ;}
   else j++;
 return i==N-1;
}


Fijemonos en como se realizan las instrucciones post decremento post incremento


#define DEC(id)         n/=id
#define INC(id)         n*=id


Esto es asi, ya que sumar 1 a la n'esima variable equivalea multiplicar el numero por el n-esimo factor primo.

M'as dificil...
Como poder evaluar i < N - 1, cuando en nuestra unica variable solo esta almacenado n=2^i*3^j ?

La estrategia sera cargar en una variable auxiliar-virtual k,n=2^i*3^j*5^k el valor de N-1-i y ver si es mayor que cero

  •   el exponente k(5) tiene que ser  igual a N, lo  que solo se puede llevar a cabo al multiplicar tantas veces por 5 como unidades tenga N
  • Como esto solo se puede saber decrementando N una unidad hasta que queda 0...al punto que multiplicamos por 5, multiplicamos por 7 (otra variable virtual l) para no perder la referencia de N en posteriores computos (que rollo!)
  • A continuacion, restauramos N, haciendo la operacion inversa, dividiendo por 7, hasta que no se pueda mas. esto es n%7==0,  ycada vez se suma 1  a N
  • Despues restamos a k (5), 1, dividiendo por 5.
  • Despues restamos i(2) a k(5), con cuidado de guardar copia en l(7) de lo que vale i  (Otra vez Un rollo!!!)
  • Restauramos en i(2), previamente guardado en el exponente de l(7)
  • Finalmente, vemos el resultado k(5) a ver si es mayor que cero. Esto ocurre si el numero n%5==0, en otro caso, k(5) es igual a 0. Convencete con n=(2^1)*(3^3)*5(^1). Ves que el resto entre 5(k) es 0, lo que no pasa con n=(2^1)*(3^3)*5(^0), cuyo resto entre 5(k) no es 0

// Expressions
#define NON_ZERO(id)    !(n % id)
#define ZERO(id)        (n%id)


Con un poco de paciencia, se puede entender el razonamiento.


  • Como es tan tedioso y proclve a errores me he creado una especie de "compilador" con las directivas de preprocesador C.
  •  El monstruo ha quedado notablemente m'as complejo que el programa anterior, pero era lo esperado... ya que, como se puede ver, solo se usa UNA variable, n)



int debug(const char *s, int n, const int i)
{
#ifdef DEBUG  
 int c;
 for( c=0; !(n%i) ; n/=i) c++;
 printf("debug STATE %s : -> %d \n",s,c);
 return c;
#endif  
}


// N Constant
#define ASSIGN_N(id1,N,id2)  for( ;N;N--) n*=id1*id2
#define RESTORE_N(N,id) for( ; !(n%id);n/=id) N++

// Restoring
#define RESTORE(id2,id3)    for( ; !(n%id3);n/=id3)  n*=id2

// Ordinary vars.
#define DEC(id)         n/=id
#define INC(id)         n*=id
#define SUBS(id1,id2,id3)   for( ; !(n%id2);n/=id2) { n/=id1; n*=id3 ;}
#define RESET(id)       for( ; !(n%id);n/=id)
#define ASSIGN(id1,id2,id3)   for( ; !(n%id2);n/=id2) n*=id1*id3
#define NEG(id)           if (n%id) n*=id; else  for( ; !(n%id);n/=id)

// Expressions
#define NON_ZERO(id)    !(n % id)
#define ZERO(id)        (n%id)

// Indirect pointers;
#define INC_POINTER(A,id1,id2) for( ; !(n%id1); n/=id1 ) { A++; n*=id2 ; }
#define INC_POINTER_POINTER(A,id1,id2) for( ; !(n%id1); n/=id1 ) { (*A)++; n*=id2;  }

#define DEC_POINTER_POINTER(A,id1,id2) for( ; !(n%id1); n/=id1 ) { (*A)--; n*=id2;  }
#define DEC_POINTER(A,id1,id2)    for( ; !(n%id1); n/=id1 ) { A--; n*=id2 ; }

int lowerTriangleDesc(const int **A, int N)
{
 int n=1;
 // i,j,k : 2,3,5    l : 7
 n=3;  // i,j,k,l=0,1,0,0
 ASSIGN_N(5,N,7);
 RESTORE_N(N,7);
 DEC(5);
 SUBS(5,2,7);
 RESTORE(2,7);
 if (NON_ZERO(5))  // if (N-1-i>0), i.e i<N-1
   {
     INC_POINTER(A,2,7); // A[i]
     RESTORE(2,7) ;
     INC_POINTER_POINTER(A,3,7); // A[i][j]
     RESTORE(3,7) ;
     if (**A)
RESET(5);
     DEC_POINTER_POINTER(A,3,7); // A[i][j]
     RESTORE(3,7) ;
     DEC_POINTER(A,2,7);
     RESTORE(2,7) ;
   } // k = k && !A[i][j]
 debug("init i",n,2); debug("init j",n,3);
 debug("B: loop i < N-1 && !A[i][j]",n,5);
 for(; NON_ZERO(5); )
   {
     RESET(5);
     ASSIGN_N(5,N,7);
     RESTORE_N(N,7);
     DEC(5);
     SUBS(5,3,7); // N-1-j > 0 , j<N-1
     RESTORE(3,7);
     if (ZERO(5))
{
 INC(2); //i++
 RESET(3);
 ASSIGN(3,2,5);
 RESTORE(2,5);
 INC(3); //j++
}
     else INC(3);
     debug("step i",n,2); debug("step j",n,3);
     ASSIGN_N(5,N,7);
     RESTORE_N(N,7);
     DEC(5);
     SUBS(5,2,7);
     RESTORE(2,7);
     if (NON_ZERO(5))  // if (N-1-i>0), i.e i<N-1
{
 INC_POINTER(A,2,7); // A[i]
 RESTORE(2,7) ;
 INC_POINTER_POINTER(A,3,7); // A[i][j]
 RESTORE(3,7) ;
 if (**A)
   RESET(5);
 DEC_POINTER_POINTER(A,3,7); // A[i][j]
 RESTORE(3,7) ;
 DEC_POINTER(A,2,7);
 RESTORE(2,7) ;
} // k = k && !A[i][j]
     debug("B: loop i < N-1 && !A[i][j]",n,5);
   }
 ASSIGN_N(5,N,7);
 RESTORE_N(N,7);
 DEC(5);
 SUBS(5,2,7);
 RESTORE(2,7);
 NEG(5);
 debug("epilogue: i==N-1",n,5);
 return NON_ZERO(5);
}


Los mensajes debug, por supuesto, son opcionales y no forman parte del codigo. Es para poder seguir mejor la codificacion de las variables en una sola.

Ah!, las pruebas de que va bien!

El codigo de IO esta en
https://foro.elhacker.net/programacion_cc/algebra_de_matrices_matriz_triangular_superior_desdendiente_en_c-t504451.0.html;msg2220794#msg2220794

$ ./main
1
1
debug STATE init i : -> 0
debug STATE init j : -> 1
debug STATE B: loop i < N-1 && !A[i][j] : -> 0
debug STATE epilogue: i==N-1 : -> 1
lowerTriangleDesc: 1
2
1 0
1 1
debug STATE init i : -> 0
debug STATE init j : -> 1
debug STATE B: loop i < N-1 && !A[i][j] : -> 1
debug STATE step i : -> 1
debug STATE step j : -> 2
debug STATE B: loop i < N-1 && !A[i][j] : -> 0
debug STATE epilogue: i==N-1 : -> 1
lowerTriangleDesc: 1
2
1 1
1 1
debug STATE init i : -> 0
debug STATE init j : -> 1
debug STATE B: loop i < N-1 && !A[i][j] : -> 0
debug STATE epilogue: i==N-1 : -> 0
lowerTriangleDesc: 0
3
1 0 0
1 1 0
1 1 1
debug STATE init i : -> 0
debug STATE init j : -> 1
debug STATE B: loop i < N-1 && !A[i][j] : -> 2
debug STATE step i : -> 0
debug STATE step j : -> 2
debug STATE B: loop i < N-1 && !A[i][j] : -> 3
debug STATE step i : -> 1
debug STATE step j : -> 2
debug STATE B: loop i < N-1 && !A[i][j] : -> 1
debug STATE step i : -> 2
debug STATE step j : -> 3
debug STATE B: loop i < N-1 && !A[i][j] : -> 0
debug STATE epilogue: i==N-1 : -> 1
lowerTriangleDesc: 1
3
1 0 0
1 1 1
1 1 1

debug STATE init i : -> 0
debug STATE init j : -> 1
debug STATE B: loop i < N-1 && !A[i][j] : -> 2
debug STATE step i : -> 0
debug STATE step j : -> 2
debug STATE B: loop i < N-1 && !A[i][j] : -> 3
debug STATE step i : -> 1
debug STATE step j : -> 2
debug STATE B: loop i < N-1 && !A[i][j] : -> 0
debug STATE epilogue: i==N-1 : -> 0
lowerTriangleDesc: 0


P.D
Si aun no te convence que es una variable...  aplica la siguiente linea en el compilador
para observar que solo existe la varaible "n" en la rutina...

gcc -E source.c -o source.hcp


el resultado es.

int lowerTriangleDesc(const int **A, int N)
{
 int n=1;

 n=3;
 for( ;N;N--) n*=5*7;
 for( ; !(n%7);n/=7) N++;
 n/=5;
 for( ; !(n%2);n/=2) { n/=5; n*=7 ;};
 for( ; !(n%7);n/=7) n*=2;
 if (!(n % 5))
   {
     for( ; !(n%2); n/=2 ) { A++; n*=7 ; };
     for( ; !(n%7);n/=7) n*=2 ;
     for( ; !(n%3); n/=3 ) { (*A)++; n*=7; };
     for( ; !(n%7);n/=7) n*=3 ;
     if (**A)
for( ; !(n%5);n/=5);
     for( ; !(n%3); n/=3 ) { (*A)--; n*=7; };
     for( ; !(n%7);n/=7) n*=3 ;
     for( ; !(n%2); n/=2 ) { A--; n*=7 ; };
     for( ; !(n%7);n/=7) n*=2 ;
   }
 debug("init i",n,2); debug("init j",n,3);
 debug("B: loop i < N-1 && !A[i][j]",n,5);
 for(; !(n % 5); )
   {
     for( ; !(n%5);n/=5);
     for( ;N;N--) n*=5*7;
     for( ; !(n%7);n/=7) N++;
     n/=5;
     for( ; !(n%3);n/=3) { n/=5; n*=7 ;};
     for( ; !(n%7);n/=7) n*=3;
     if ((n%5))
{
 n*=2;
 for( ; !(n%3);n/=3);
 for( ; !(n%2);n/=2) n*=3*5;
 for( ; !(n%5);n/=5) n*=2;
 n*=3;
}
     else n*=3;
     debug("step i",n,2); debug("step j",n,3);
     for( ;N;N--) n*=5*7;
     for( ; !(n%7);n/=7) N++;
     n/=5;
     for( ; !(n%2);n/=2) { n/=5; n*=7 ;};
     for( ; !(n%7);n/=7) n*=2;
     if (!(n % 5))
{
 for( ; !(n%2); n/=2 ) { A++; n*=7 ; };
 for( ; !(n%7);n/=7) n*=2 ;
 for( ; !(n%3); n/=3 ) { (*A)++; n*=7; };
 for( ; !(n%7);n/=7) n*=3 ;
 if (**A)
   for( ; !(n%5);n/=5);
 for( ; !(n%3); n/=3 ) { (*A)--; n*=7; };
 for( ; !(n%7);n/=7) n*=3 ;
 for( ; !(n%2); n/=2 ) { A--; n*=7 ; };
 for( ; !(n%7);n/=7) n*=2 ;
}
     debug("B: loop i < N-1 && !A[i][j]",n,5);
   }
 for( ;N;N--) n*=5*7;
 for( ; !(n%7);n/=7) N++;
 n/=5;
 for( ; !(n%2);n/=2) { n/=5; n*=7 ;};
 for( ; !(n%7);n/=7) n*=2;
 if (n%5) n*=5; else for( ; !(n%5);n/=5);
 debug("epilogue: i==N-1",n,5);
 return !(n % 5);
}


SE PUEDE HACER CON UN SOLO BUCLE

DE NUEVO, EL COSTE A PAGAR SERA UN CONTROL MAS COMPLEJO,

AQUI LO DEJO.
Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)