Mostrando entradas con la etiqueta ALGEBRA. Mostrar todas las entradas
Mostrando entradas con la etiqueta ALGEBRA. Mostrar todas las entradas

sábado, 4 de junio de 2016

Método de Jacobi de resolución de sistemas programado en C/C++

Método de Jacobi programado en C/C++ para la resolución de sistemas lineares de ecuaciones:

El método Jacobi es el método iterativo para resolver sistemas de ecuaciones lineales más simple y se aplica sólo a sistemas cuadrados, es decir a sistemas con tantas incógnitas como ecuaciones, del tipo:
                                                                   Ax=b

Idea:
1-Separar la matriz A en su diagonal (D) y en su matrices estrictamente superior (U) e inferior (L):
                                                                  A=D+L+U=D+R
2-Reescribir el sistema con este desarrollo de la matriz A:
                                                                  b-(D+R)x=0
                                                                  b-Rx=Dx
                                                                  D^(-1)(b-Rx)=x
3- A partir de esta ultima expresion se itera tomando un valor inicial de x denominado x0:
                                                                  D^(-1)(b-Rx(i))=x(i+1)
donde x(i) hace referencia al valor de x en la iteración i.
Hay que notar que la complejidad de calcular la inversa de la matriz diagonal es nula:
                                                                 D^(-1)(i,i)=1/D^(-1)(i,i)

Nota: El método de Jacobi siempre converge si la matriz A es estrictamente diagonal dominante y puede converger incluso si esta condición no se satisface.

Dejo aquí los enlaces a otros metodos de resolucion de sistemas programados en C y en PASCAL:

JACOBI en PASCAL: http://cypascal.blogspot.fr/2012/03/resolucion-de-sistemas-mediante-jacobi.html
GAUSS en C: http://cypascal.blogspot.fr/2012/10/metodo-de-gauss-en-cc.html
GAUSS en PASCAL: http://cypascal.blogspot.fr/2012/10/metodo-de-gauss-en-cc.html
LU en PASCAL:http://cypascal.blogspot.fr/2012/02/factorizacion-lu.html

Código:

#include <stdio.h>
#include <stdlib.h>

int dim;
float norma(float vector1[],float vector2[]);
float suma_jacobi(float Matriz[], float vector[], int componente);

int main(){
    int i,j,iteraciones=0;
    float error,epsilon;
    printf("\n METODO DE JACOBI DE RESOLUCION DE SISTEMAS Ax=b \n");

    printf("Dimension de la matriz A: ");
    scanf("%d",&dim);
    float A[dim][dim],b[dim],x[dim],x_prev[dim],aux[dim];

    printf("\n Elementos de la matriz A: \n");
    for(i=0;i<dim;i++) for(j=0;j<dim;j++){
        printf("A(%d,%d)=",i,j); scanf("%f",&A[i][j]);
    }

    printf("\n Elementos del vector b: \n");
    for(i=0;i<dim;i++){
        printf("b(%d)=",i); scanf("%f",&b[i]);
    }

    printf("\n Error de parada: \n");
    printf("E=",i); scanf("%f",&epsilon);
    error=epsilon+1;

    //cominezo algoritmo de Jacobi
    //Error se mide como la norma del vector diferenceia entre la iteracion i e i+1
    printf("\n Valor inicail de la iteracion: \n");
    for(i=0;i<dim;i++){
        printf("x0(%d)=",i); scanf("%f",&x_prev[i]);
    }
    while (error>epsilon){
        for(i=0;i<dim;i++){
            for(j=0;j<dim;j++) aux[j]=A[i][j];
            x[i]=(1/A[i][i])*(b[i]-suma_jacobi(aux,x_prev,i));
        }
        error=norma(x,x_prev);

        printf("\n\n Iteracion %d: \n",iteraciones);
        for(i=0;i<dim;i++){
            x_prev[i]=x[i];
            printf("X(%d)=%f \n",i,x[i]);
        }

        iteraciones++;
        if (iteraciones==10) error=epsilon-1;
    }

    printf("Solucion del sistema\n");
    printf("Numero de iteraciones: %d \n", iteraciones);
    for(i=0;i<dim;i++){
        printf("x(%d)=%f\n",i,x[i]);
    }
    return 1;
}

float norma(float vector1[],float vector2[]){
    float aux=0;
    int i;
    for(i=0;i<dim;i++){
        aux=aux+(vector1[i]-vector2[i])*(vector1[i]-vector2[i]);
    }
    return aux;
}

float suma_jacobi(float Matriz[], float vector[], int componente)
{
    float aux=0;
    int i;
    for(i=0;i<dim;i++){
        if (componente!=i){
            aux=aux+Matriz[i]*vector[i];
        }
    }
    return aux;
}


Salu10

martes, 16 de octubre de 2012

Metodo de Gauss en C/C++

El siguiente programa muestra el método de Gauss y su aplicación para resolver sistemas de Ecuaciones en C. Este programa ya fue implementado en Pascal: (http://cypascal.blogspot.com.es/2011/07/metodo-de-gauss.html)
aunque en este programa hemos trabajado de manera más sistematica, quedando un programa con muchas menos lineas e igual de efectivo. Este programa solo trabaja con sistemas de ecuaciones lineales con una única solución determinada, y que sean compatibles. Este programa del metodo de Gauss para la resolución de sistemas de ecuaciones en C, incluye una función que es la encargada de resolver el sistema y que se llama ResuelveGauss. Esta función será utilizada a la hora de resolver el sistema que da lugar el método de Mínimos Cuadrados y el cálculo del determinante.
Otro método que tambien permite resolver sitemas de ecuaciones, esta vez de forma iterativa, es el método de Jacobi. En los dos siguientes enlaces pueden encontrar los códigos tanto en C como en Pascal: Jacobi en C y Jacobi en Pascal

Mínimos cuadrados: .http://cypascal.blogspot.com.es/2012/10/minimos-cuadrados-en-cc.html.
Determinante: http://cypascal.blogspot.com.es/2013/04/calculo-determinante-en-c.html

#include <stdio.h>

void PideDatos(int *Dim, float Sist[][102]);
void EscribeDatos(int Dim, float Sist[][102]);

void ResuelveGauss(int Dim, float Sist[][102]);


int main(void)
{
    int C,Dimension;
    float Sistema[101][102];
    PideDatos(&Dimension,Sistema);
    printf("\n\n\nEl SISTEMA introducido es el siguiente: \n\n");
    EscribeDatos(Dimension,Sistema);
    ResuelveGauss(Dimension,Sistema);
    printf("\n\n\nLas soluciones son:\n");
    for(C=1;C<=Dimension;C++) printf("\n X%d=%f\n",C,Sistema[C][Dimension+1]);
   
    scanf("");
    return(0);
}


void PideDatos(int *Dim,float Sist[][102])
{
    int A,B;
    printf("\n\n ||RESUELVE SISTEMAS LINEALES DETERMINADOS POR GAUSS||");
    printf("\n\n\n Introduce el numero de incognitas:(menor que 100)");
    scanf("%d",&*Dim);
    printf("\n\n PASE A INTRODUCIR CADA COMPONENTE DEL SISTEMA (A|B):");
    printf("\n\n MATRIZ A:\n");
    for(A=1;A<=*Dim;A++) for(B=1;B<=*Dim;B++){
        printf("\n Termino A(%d,%d):",A,B); scanf("%f",&Sist[A][B]);}
    printf("\n\n\n VECTOR B:\n");
    for(A=1;A<=*Dim;A++){
        printf("\n Termino B(%d):",A);scanf("%f",&Sist[A][*Dim+1]);
    }}

void EscribeDatos(int Dim, float Sist[][102])
{
    int A,B;
    for(A=1;A<=Dim;A++){
        for(B=1;B<=(Dim+1);B++){
            printf("%7.2f",Sist[A][B]);
            if(B==Dim) printf("   |");}
        printf("\n");
    }}

void ResuelveGauss(int Dim, float Sist[][102])
{
    int NoCero,Col,C1,C2,A;
    float Pivote,V1;
   
    for(Col=1;Col<=Dim;Col++){
        NoCero=0;A=Col;
        while(NoCero==0){
            if(Sist[A][Col]!=0){
                NoCero=1;}
            else A++;}
        Pivote=Sist[A][Col];
        for(C1=1;C1<=(Dim+1);C1++){
            V1=Sist[A][C1];
            Sist[A][C1]=Sist[Col][C1];
            Sist[Col][C1]=V1/Pivote;}
        for(C2=Col+1;C2<=Dim;C2++){
            V1=Sist[C2][Col];
            for(C1=Col;C1<=(Dim+1);C1++){
                Sist[C2][C1]=Sist[C2][C1]-V1*Sist[Col][C1];}
    }}
   
    for(Col=Dim;Col>=1;Col--) for(C1=(Col-1);C1>=1;C1--){
        Sist[C1][Dim+1]=Sist[C1][Dim+1]-Sist[C1][Col]*Sist[Col][Dim+1];
        Sist[C1][Col]=0;
    }
}



Se podría poner un numero pequeño en vez de cero para que no diera problemas. Hay que tener en cuenta, que a la hora de operar, es posible que en vez de obtener 0s obtengamos número muy pequeños pero no ceros. Aquí les dejo el código con esa pequeña corrección:
Codigo con mejora

Salu10!

martes, 14 de febrero de 2012

QR descomposition (Mediante Gram)

In linear algebra, a QR decomposition (also called a QR factorization) of a matrix is a decomposition of a matrix A into a product A=QR of an orthogonal matrix Q and an upper triangular matrix R. QR decomposition is often used to solve the linear least squares problem,
We can use QR decomposition to find the absolute value of the determinant of a square matrix;
det(A)=det(Q)*det(R)=1*det(R) 
and determiant of a upper triangular matrix is very easy:

program QR(input,output);
const
  tanMax=20;

type
  tpDimension=1..tanMax;
  tpContador=1..MAXINT;
  tpVector=array[1..tanMax] of real;
  tpMatriz=record
    m:array[1..tanMax] of tpVector;
    f,c:tpDimension
  end;

var
  A,Q,R,B:tpMatriz;{x,y,z,b}

procedure CargaDatos(VAR x:tpMatriz);
  var
    i,j:tpContador;
  begin
    writeln('QR DESCOMPOSITION:'); writeln;
    write('Number of rows: ');readln(x.f);
    write('Number of Columns: ');readln(x.c);
    writeln;
    for i:=1 to x.f do begin
        for j:=1 to x.c do begin
          write('Position (',i,',',j,'): ');readln(x.m[i,j]) end;
      writeln
    end
  end;

procedure EscribirMatriz(x:tpMatriz);
var
  i,j:tpContador;

begin
  writeln;
  for i:=1 to x.f do begin
    for j:=1 to x.c do
      write(x.m[i,j]:7:3,' ');
    writeln
  end;
  writeln; writeln
end;

function aux(y,x:tpMatriz; n,i:tpContador):real;
  var
    j:tpContador;
    aux1,aux2:real;
  begin
    aux1:=0;
    aux2:=0;
    for j:=1 to x.f do begin
      aux1:=aux1+x.m[j,n]*y.m[j,i];
      aux2:=aux2+y.m[j,i]*y.m[j,i]
    end;
    aux:=aux1/aux2
  end;

procedure ortogonaliza(VAR y:tpMatriz; x:tpMatriz);
  var
    i,j,n:tpContador;
    a:real;

  begin
  y.f:=x.f; y.c:=x.c;
  for n:=1 to x.f do begin
    for j:=1 to x.f do y.m[j,n]:=x.m[j,n];
    for i:=1 to (n-1) do begin
      a:=aux(y,x,n,i);
      for j:=1 to x.f do
        y.m[j,n]:=y.m[j,n]-a*y.m[j,i]
      end
    end;
  end;

procedure normaliza(VAR y:tpMatriz);
  var
    i,j:tpContador;
    a:real;
  begin
    for i:=1 to y.c do begin
      a:=0;
      for j:=1 to y.f do
        a:=a+y.m[j,i]*y.m[j,i];
      a:=sqrt(a);
      for j:=1 to y.f do
        y.m[j,i]:=y.m[j,i]/a
    end
  end;

procedure transponer(VAR b:tpMatriz; x:tpMatriz);
  var
    i,j:tpContador;
  begin
    b.f:=x.c; b.c:=x.f;
    for i:=1 to b.f do
      for j:=i to b.c do begin
        b.m[i,j]:=x.m[j,i];
        b.m[j,i]:=x.m[i,j]
      end
  end;

procedure multiplica(VAR x:tpMatriz; y,z:tpMatriz);
  {multiplica Y*Z en este orden y lo guarda en X (Y.c=Z.f)}
  var
    i,j,k:tpDimension;
  begin
    x.f:=y.f; x.c:=z.c;
    for i:=1 to y.f do
      for j:=1 to z.c do begin
        x.m[i,j]:=0;
        for k:=1 to y.c do x.m[i,j]:=x.m[i,j]+y.m[i,k]*z.m[k,j]
      end
  end;


{comienzo del programa}
begin
  CargaDatos(A);
  EscribirMatriz(A);
  ortogonaliza(Q,A);
  normaliza(Q);
  transponer(B,Q);
  multiplica(R,B,A);
  writeln('Matrix Q:'); EscribirMatriz(Q);
  writeln('Matrix R:'); EscribirMatriz(R);
  multiplica(B,Q,R);
  writeln('QR is:'); EscribirMatriz(B);
  writeln('It should to be like A');
  readln
end.

Salud.


lunes, 13 de febrero de 2012

Obtención de Base ortogonal mediante Gram-Schmidt

El siguiente programa está dedicado al cálculo de una base ortogonal a partir de un conjunto de vectores linealmente independiente, tomándose como producto escalar el producto escalar usual, mediante el método de Gram. Este método se puede deducir de manera sencilla, y es una de las maneras más simples de calcular una base ortogonal.
El mecanismo del programa es el siguiente:
  1.   Se introducen las componentes de los vectores en una matriz, que se triangulariza superior. En el caso de que el último pivote sea 0, quiere decir que hay por lo menos un vector que es combinación lineal de los demás, con lo cual no forman una base, si acaso un sistema generador de un espacio vectorial.
  2. Se aplica el método de Gram (que en realidad se atribuye a Laplace) escogiendo los vectores en el orden en que han sido introducidos (dependiendo del orden de los mismos la base será distinta, pero todas generarán el mismo espacio).
  3. Se dividen los vectores de la base ortognal por su norma, de manera que sean vectores unitarios que forman una base ortonormal.

{programa que apartir de unos vectores que forman una base de un espacio vectorial
(deben ser linealmente independientes) devuelve una base ortonormal respecto al
producto escalar usual. Basado en el metodo de Gram-Schmidt}

program gram(input,output);
const
  tanMax=20;

type
  tpDimension=1..tanMax;
  tpContador=1..MAXINT;
  tpVector=array[1..tanMax] of real;
  tpMatriz=array[1..tanMax] of tpVector;

var
  mat,matorto:tpMatriz;
  vectores,componentes:tpDimension;


procedure EscribirMatriz(m:tpMatriz; filas,columnas:tpDimension);
  var
    i,j:tpContador;

  begin
    for i:=1 to filas do begin
      write('Vector:',i,':    (');
      for j:=1 to columnas do
        write(m[i,j]:7:2,' ');
      writeln(')');
    end
  end;

procedure CargaVectores(VAR v,c:tpDimension; VAR m:tpMatriz);
  var
    i,j:tpContador;
  begin
    write('Introduzca el numero de vectores: ');readln(v);
    write('Introduzca el numero de componentes: ');readln(c);
    for i:=1 to v do begin
      writeln('Vector numero ',i,':');
        for j:=1 to c do begin
          write('Componenetes numero ',j,': ');readln(m[i,j]) end;
      writeln
    end
  end;

function lineal(matriz:tpMatriz; columnas,filas:tpDimension):boolean;
  Const
    precision=0.000001;

  Var
    min,pasoF,pasoC:tpDimension;
    cont:tpContador;

  Procedure SeleccionarFila(f,c,pF,pC:tpDimension; VAR m:tpMatriz);
    Var
      i,j:tpContador;
      aux:real;

    Begin
      i:=pF;
      while (m[i,pC]<precision) and (i<f) and (m[i,pC]>-precision) do
        i:=i+1;
      If i<>f then
        begin
          for j:=pC to c do begin
            aux:=m[pF,j];
            m[pF,j]:=m[i,j];
            m[i,j]:=aux
          end
        end
    end;


  Procedure restarFilas(f,c:tpDimension; VAR pF:tpDimension; VAR pC:tpDimension; VAR m:tpMatriz);
    var
      i,j:tpContador;
      aux:real;

    begin
      if m[pF,pC]<>0 then begin
        for i:=(pF+1) to f do begin
          aux:=m[i,Pc];
          for j:=pC to c do
            m[i,j]:=m[i,j]-aux*(m[pF,j]/m[pF,pC]);
        end;
        pF:=pF+1
      end;
      pC:=pC+1
    end;


  procedure MinDim(f,c:tpDimension; VAR mini:tpDimension);
    begin
      if c<f then mini:=c else mini:=f
    end;

  begin
    MinDim(filas,columnas,min);
    pasoF:=1; pasoC:=1;
    for cont:=1 to min do
      begin
        SeleccionarFila(filas,columnas,pasoF,pasoC,matriz);
        restarFilas(filas,columnas,pasoF,pasoC,matriz)
      end;
    if (matriz[filas,columnas]<precision) and (matriz[filas,columnas]>-precision) then
      lineal:=false
    else
      lineal:=true
  end;
{final de la function lineal}

function aux(morto,m:tpMatriz; n,i,comp:tpContador):real;
  var
    j:tpContador;
    aux1,aux2:real;
  begin
    aux1:=0;
    aux2:=0;
    for j:=1 to comp do begin
      aux1:=aux1+m[n,j]*morto[i,j];
      aux2:=aux2+morto[i,j]*morto[i,j]
    end;
    aux:=aux1/aux2
  end;

procedure ortogonaliza(VAR morto:tpMatriz; m:tpMatriz; comp:tpContador);
  var
    i,j,n:tpContador;
    a:real;

  begin
  for n:=1 to vectores do begin
    for j:=1 to comp do morto[n,j]:=m[n,j];
    for i:=1 to (n-1) do begin
      a:=aux(morto,m,n,i,comp);
      for j:=1 to comp do
        morto[n,j]:=morto[n,j]-a*morto[i,j]
      end
    end;
  end;

procedure normaliza(VAR morto:tpMatriz);
  var
    i,j:tpContador;
    a:real;
  begin
    for i:=1 to vectores do begin
      a:=0;
      for j:=1 to componentes do
        a:=a+morto[i,j]*morto[i,j];
      a:=sqrt(a);
      for j:=1 to componentes do
        morto[i,j]:=morto[i,j]/a
    end
  end;

{comienzo programa}
begin
  writeln('OBTIENE BASE ORTOGONAL Y OROTONORMAL MEDIANTE GRAM-SCHMIDT');
  writeln;
  CargaVectores(vectores,componentes,mat);
  writeln;
  writeln('Vectores Introducidos:');
  EscribirMatriz(mat,vectores,componentes);writeln;writeln;
  If lineal(mat,componentes,vectores) then
    begin
      ortogonaliza(matorto,mat,componentes);
      writeln('Base ortogonal del Espacio engendrado por los vectores introducidos: ');
      EscribirMatriz(matorto,vectores,componentes);writeln;writeln;
      normaliza(matorto);
      writeln('Base ortonormal del Espacio engendrado por los vectores introducidos: ');
      EscribirMatriz(matorto,vectores,componentes);writeln;writeln;
    end
  else
    writeln('El conjunto de vectores no es base puesto que no es linealmente independiente');
  writeln;
  readln
end.

jueves, 21 de julio de 2011

CÁLCULO DEL DETERMINANTE

  El siguiente programa permite el cálculo del determinante de una matriz de cualquier tamaño, este cálculo resulta muy pesado y muy costoso para el ordenador, y los resultados para matrices de ordenes bajos (entorno 10x10) pueden superar el valor de MAXINT y dar valores erróneos.
  El método está basado en el desarrollo de Laplace (Nada de Sarrus ni cosas rara...) aplicado a la primera columna de la matriz (importante que sea la primera, puesto que una matriz de 1x1 solo tiene una, y si se pone que se aplique siempre en la segunda daría error), el cual consiste en multiplicar los términos de una columna o fila por su adjunto (no me explayo más, sino queda  claro consultar libros de álgebra. J. de Burgos siempre está bien). Para el cálculo del determinante se usa exclusivamente una función recursiva (Es una función que es llamada dentro de ella misma) la cual le otorga una elegante imagen al método, haciéndolo  breve y claro (tampoco sé si se podrá hacer de alguna otra manera...).



program Determinante(input,output);
uses crt;

const
  maxdim=100;

type
  tpContador=0..MAXINT;
  tpMatriz=record
    dim:tpContador;
    vals:array[1..maxdim,1..maxdim] of real
  end;

var
  matriz:tpMatriz;

procedure PideValores(VAR matriz:tpMatriz);
  var
    c1,c2:tpContador;

  begin
    write('Introduzca la dimension de la matriz: ');readln(matriz.dim);
    for c1:=1 to matriz.dim do
      for c2:=1 to matriz.dim do begin
        write('Introduzca el termino (',c1,',',c2,'): ');readln(matriz.vals[c1,c2])
      end
  end;

procedure DibujaMatriz(matriz:tpMatriz);
  var
    c1,c2:tpContador;
  begin
    for c1:=1 to matriz.dim do begin
      for c2:=1 to matriz.dim do
        write(matriz.vals[c1,c2]:10:2);
      writeln
    end
  end;

function Det(matriz:tpMatriz):real;
  var
    c1,c2,c3,paso:tpContador;
    matrizAux:tpMatriz;
    detaux:real;
    signo:integer;
  begin
    detaux:=0;
    if matriz.dim>1 then
      for c1:=1 to matriz.dim do begin
        paso:=0;
        matrizAux.dim:=matriz.dim-1;
        for c2:=2 to matriz.dim do begin
          paso:=0;{Es el desarrolo de Laplace del determinante para la primera columna}
          for c3:=1 to matriz.dim do
            if c3<>c1 then begin
              paso:=paso+1;
              {writeln('c1:',c1,'   c2:',c2,'   c3:',c3);}
              matrizAux.vals[paso,c2-1]:=matriz.vals[c3,c2]
            end
        end;
        {DibujaMatriz(matrizAux);writeln;}
        if (c1 mod 2)<>1 then signo:=-1 else signo:=1;
        detaux:=detaux+matriz.vals[c1,1]*signo*det(matrizAux);
      end
    else
      detaux:=matriz.vals[1,1];
    det:=detaux
  end;

begin
  writeln('Calcula el determiante');
  PideValores(matriz);writeln;writeln;writeln('La matriz introducida es: ');writeln;
  DibujaMatriz(matriz);writeln;writeln;
  {writeln('El determinante es: ');}writeln(Det(matriz));
  readln
end.