[net.sources] Matrix Routines in C

pjs269@tijc02.UUCP (Paul Schmidt ) (04/21/86)

This message is the code I wrote for my Numerical
Computing class at East Tennessee State University.
Instead of doing the "old rm" now that the course is over,
I am posting it on the net hoping that I may save someone
some time.

The bulk of the code exists as routines that I put into
the library "libMAT.a".  These routines have a header
block telling what parameters are used and a small description
of what it does.  These routines have not been fully debugged
but were run with various test data with no problems.

In all the library routines I define a matrix as:
    double  **matrix;
You reference an element in the matrix by matrix[x][y].
The mat_new function allocates the space for the matrix and
mat_free frees the space used by the matrix.

Some of the algorithms are from the book Numerical Analysis by
Burden, Faires, and Reynolds.  This book, or other numerical
computing books can give a complete explanation of each routine.

I have also supplied the following programs that use the library
routines:
    add     -   add two matrices.
    mult    -   multiply two matrices.
    gauss   -   Gaussian elimination routine with backward
                substitution to solve a system of equations.
    SOR     -   Successive Over-relaxation algorithm used to
                solve a system of equations.
    least_sq -  Find the least square equation of degree n for
                a set of data points.
    w_least -   Use weighted least sqaure algorithm to find a
                polynomial of degree n for a set of data points.

If anyone has any problems with this code or has any comments
please send me mail.

Good luck,
        Paul J. Schmidt
        Texas Instruments
        P.O. Drawer 1255 M/S 3520
        Johnson City, TN 37601

E-Mail:
        decvax!mcnc!rti-sel!tijc02!pjs269

#--------------------------- CUT HERE -----------------------------------
#!/bin/sh
# Cut above the preceeding line, or cut here if you must.
# This is a shar archive.  Extract with sh, not csh.
# The rest of this file will extract:
#	 Makefile
#	 README
#	 SOR.c
#	 add.c
#	 gauss.c
#	 least_sq.c
#	 mat_SOR.c
#	 mat_add.c
#	 mat_backward.c
#	 mat_copy.c
#	 mat_free.c
#	 mat_gauss.c
#	 mat_least.c
#	 mat_mult.c
#	 mat_new.c
#	 mat_print.c
#	 mat_remove.c
#	 mat_scale.c
#	 mat_scan.c
#	 mat_trans.c
#	 mat_w_least.c
#	 matrix.h
#	 mult.c
#	 norm_2.c
#	 norm_inf.c
#	 row_add.c
#	 row_scale.c
#	 row_swap.c
#	 w_least.c
sed 's/^X//' > Makefile << '/*EOF'
X#
X#   Makefile for the matrix routines
X#
X
XCFLAGS= -O
XLIB_NAME=MAT
XLIB=lib$(LIB_NAME).a
X
XFILES=$(LIB)(mat_least.o) $(LIB)(mat_w_least.o)\
X	$(LIB)(mat_SOR.o) $(LIB)(mat_gauss.o)\
X	$(LIB)(mat_add.o) $(LIB)(mat_backward.o)\
X	$(LIB)(mat_copy.o) $(LIB)(mat_free.o)\
X	$(LIB)(mat_mult.o) $(LIB)(mat_new.o)\
X	$(LIB)(mat_print.o) $(LIB)(mat_remove.o) $(LIB)(mat_scale.o)\
X	$(LIB)(mat_scan.o) $(LIB)(mat_trans.o)\
X	$(LIB)(row_add.o) $(LIB)(row_scale.o) $(LIB)(row_swap.o)\
X	$(LIB)(norm_2.o) $(LIB)(norm_inf.o)
X
Xall: lib SOR add gauss least_sq mult w_least
X#
X#   make the library.
X#
X
Xlib:    $(FILES)
X
XSOR:    SOR.c $(LIB) matrix.h
X	cc $(CFLAGS) -o SOR SOR.c $(LIB) -lm
X
Xgauss:  gauss.c $(LIB) matrix.h
X	cc $(CFLAGS) -o gauss gauss.c $(LIB)
X
Xleast_sq:   least_sq.c $(LIB) matrix.h
X	cc $(CFLAGS) -o least_sq least_sq.c $(LIB)
X
Xw_least:    w_least.c $(LIB) matrix.h
X	cc $(CFLAGS) -o w_least w_least.c $(LIB)
X
Xadd:    add.c $(LIB) matrix.h
X	cc $(CFLAGS) -o add add.c $(LIB)
X
Xmult:   mult.c $(LIB) matrix.h
X	cc $(CFLAGS) -o mult mult.c $(LIB)
/*EOF
ls -l Makefile
sed 's/^X//' > README << '/*EOF'
XThis file describes the code I wrote for my Numerical
XComputing class at East Tennessee State University.
XInstead of doing the "old rm" now that the course is over,
XI am posting it on the net hoping that I may save someone
Xsome time.
X
XThe bulk of the code exists as routines that I put into
Xthe library "libMAT.a".  These routines have a header
Xblock telling what parameters are used and a small description
Xof what it does.  These routines have not been fully debugged
Xbut were run with various test data with no problems.
X
XIn all the library routines I define a matrix as:
X    double  **matrix;
XYou reference an element in the matrix by matrix[x][y].
XThe mat_new function allocates the space for the matrix and
Xmat_free frees the space used by the matrix.
X
XSome of the algorithms are from the book Numerical Analysis by
XBurden, Faires, and Reynolds.  This book, or other numerical
Xcomputing books can give a complete explanation of each routine.
X
XI have also supplied the following programs that use the library
Xroutines:
X    add     -   add two matrices.
X    mult    -   multiply two matrices.
X    gauss   -   Gaussian elimination routine with backward
X                substitution to solve a system of equations.
X    SOR     -   Successive Over-relaxation algorithm used to
X                solve a system of equations.
X    least_sq -  Find the least square equation of degree n for
X                a set of data points.
X    w_least -   Use weighted least sqaure algorithm to find a
X                polynomial of degree n for a set of data points.
X
XIf anyone has any problems with this code or has any comments
Xplease send me mail.
X
XGood luck,
X        Paul J. Schmidt
X        Texas Instruments
X        P.O. Drawer 1255 M/S 3520
X        Johnson City, TN 37601
X
XE-Mail:
X        decvax!mcnc!rti-sel!tijc02!pjs269
X
/*EOF
ls -l README
sed 's/^X//' > SOR.c << '/*EOF'
X/*
X**  SOR
X**
X**      Program to use Successive Over-Relaxation to solve a system
X**  of equations.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 March 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**  Reference:  Numerical Analysis;
X**              Burden, Faires, and Reynolds;
X**              page 391
X*/
X
X#include <stdio.h>
X#include "matrix.h"
X
Xmain()
X{
X    extern  double  **mat_new();
X
X    double  **matrix, **x, error, omega;
X    int     m, n;
X    int     max_iterations;
X
X    fprintf(stderr, "Input size: ");
X    scanf("%d %d", &m, &n);
X    matrix = mat_new(m, n);
X    fprintf(stderr, "Input matrix: \n");
X    mat_scan("%g", matrix, m, n);
X    printf("System of equations:\n");
X    mat_print("%10.6g ", matrix, m, n);
X    x = mat_new(m, 1);
X    fprintf(stderr, "Initial guess: \n");
X    mat_scan("%g", x, m, 1);
X    printf("Input initial approximation:\n");
X    mat_print("%10.6g ", x, m, 1);
X    fprintf(stderr, "What is the tolerance?  ");
X    scanf("%lg", &error);
X    fprintf(stderr, "What is the omega?  ");
X    scanf("%lg", &omega);
X    fprintf(stderr, "What is the maximum number of iterations?  ");
X    scanf("%d", &max_iterations);
X    printf("Tolerance = %lg, omega = %lg, max iterations = %d\n", error, omega, max_iterations);
X    if (mat_SOR(matrix, m, x, error, omega, max_iterations) != OK)
X        printf("Maximum nuber of iterations exceeded.\n");
X    printf("Best approximation:\n");
X    mat_print("%10.6g ", x, m, 1);
X    mat_free(matrix, m, n);
X    exit(0);
X}
/*EOF
ls -l SOR.c
sed 's/^X//' > add.c << '/*EOF'
X/*
X**  Program to add two matrices.
X**
X**  Author:     Paul Schmidt
X**  Date:       February 1986
X*/
X
X#include    <stdio.h>
X
Xmain()
X{
X    extern  double  **mat_new();
X
X    double  **a, **b, **sum;
X    int     m, n, m1, n1;
X
X    fprintf(stderr,"Input size: ");
X    scanf("%d %d", &m, &n);
X    a = mat_new(m, n);
X    fprintf(stderr,"Input matrix: \n");
X    mat_scan("%g",a , m, n);
X    fprintf(stderr,"Input size: ");
X    scanf("%d %d", &m1, &n1);
X    if ((m != m1) || (n != n1))
X    {
X        mat_free(a, m, n);
X        fprintf(stderr,"add error: Matrices not the same size\n");
X        exit(-1);
X    }
X    b = mat_new(m, n);
X    fprintf(stderr,"Input matrix: \n");
X    mat_scan("%g", b, m, n);
X    sum = mat_new(m, n);
X    mat_add(sum, a, b, m, n, (double)1.0);
X    mat_free(a, m, n);
X    mat_free(b, m, n);
X    fprintf(stderr,"Matrix sum:\n");
X    printf("%d %d\n", m, n);
X    mat_print("%10.6g ", sum, m, n);
X    mat_free(sum, m, n);
X    exit(0);
X}
/*EOF
ls -l add.c
sed 's/^X//' > gauss.c << '/*EOF'
X/*
X**  Gauss
X**
X**      Program to use gaussian elimination to solve matrices.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**  Reference:  Numerical Analysis
X**              Burden, Faires, and Reynolds
X**              pages 268-269
X**
X*/
X
X#include    <stdio.h>
X#include    "matrix.h"
X
Xmain()
X{
X    extern  double  **mat_new();
X
X    double  **matrix;
X    int     m, n;
X
X    fprintf(stderr,"Input size: ");
X    scanf("%d %d", &m, &n);
X    matrix = mat_new(m, n);
X    fprintf(stderr,"Input matrix: \n");
X    mat_scan("%g", matrix, m, n);
X    if (mat_gauss(matrix, m) == NON_UNIQUE)
X        printf("Matrix results in non_unique solutions.\n");
X    printf("Reduced matrix:\n");
X    mat_print("%-10.6g ", matrix, m, n);
X    mat_free(matrix, m, n);
X    exit(0);
X}
/*EOF
ls -l gauss.c
sed 's/^X//' > least_sq.c << '/*EOF'
X/*
X**  least_sq
X**
X**      Program to approximate a polynomial by using least squares.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X*/
X
X#include    <stdio.h>
X#include    "matrix.h"
X
Xmain()
X{
X    double  **x, **y, **coef, **resid;
X    int     number, degree, i;
X
X    extern  double  **mat_new();
X
X    fprintf(stderr, "Program to calculate a polynomial using least squares.\n");
X    fprintf(stderr, "What is the degree of the polynomial?  ");
X    scanf("%d", &degree);
X    fprintf(stderr, "How many data points?  ");
X    scanf("%d", &number);
X    x = mat_new(number, 1);
X    y = mat_new(number, 1);
X    fprintf(stderr, "Input data points (x y):\n");
X    for (i=0; i<number; i++)
X    {
X        scanf("%g", &(x[i][0]));
X        scanf("%g", &(y[i][0]));
X    }
X
X    /* Echo the data points */
X    printf("%-10s %-10s\n", "  X  ", "  Y  ");
X    for (i=0; i<number; i++)
X        printf("%- 010.6g %- 010.6g\n", x[i][0], y[i][0]);
X
X    /* Allocate space for the coefficients and residuals and call the
X        least squares routine. */
X    resid = mat_new(number, 1);
X    coef = mat_new(degree+1, 1);
X    if (mat_least(x, y, number, degree, coef, resid) != OK)
X    {
X        fprintf(stderr, "Least sqaure calculation failed\n");
X        exit(-1);
X    }
X
X    printf("\nThe approximating polynomial:\n");
X    for (i=0; i<=degree; i++)
X    {
X        if (i==0)
X            printf("Y = %g ", coef[i][0]);
X        if (i==1)
X            printf("%gX ", coef[i][0]);
X        if (i>1)
X            printf("%gX^%d ", coef[i][0], i);
X        if (i != degree)
X            printf("+ ");
X    }
X    printf("\n");
X
X    printf("\nThe residuals for the data points are:\n");
X    mat_print("%- 010.6g", resid, number, 1);
X
X    /* Free the matrices */
X    mat_free(x, number, 1);
X    mat_free(y, number, 1);
X    mat_free(coef, degree+1, 1);
X    mat_free(resid, number,1);
X
X    /* Exit the program successfully */
X    exit(0);
X}
/*EOF
ls -l least_sq.c
sed 's/^X//' > mat_SOR.c << '/*EOF'
X/*
X**  mat_SOR
X**
X**      Iterative algorithm using Succesive Over-Relaxation to solve
X**  a linear system.
X**
X**  Input:
X**      a       -   The system of equations.
X**      m       -   The number of unknowns and equations.
X**      xo      -   A nx1 matrix for the initial approximation.
X**      error   -   Error bound used for stopping criterium.
X**      omega   -   Relaxation factor.
X**      max_it  -   Maximum number of iterations.
X**
X**  Output:
X**      xo      -   The nxn matrix to solve the system.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 March 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**  Reference:  Numerical Analysis
X**              Burden, Faires, and Reynolds
X**              page 391
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xmat_SOR(a, m, xo, error, omega, max_it)
Xdouble  **a;
Xint     m;
Xdouble  **xo;
Xdouble  error;
Xdouble  omega;
Xint     max_it;
X{
X    extern  double  **mat_new();
X    extern  double  norm_2();
X    int     i, j, k;
X    double  sum1, sum2;
X    double  **x, **diff;
X
X    /* Allocate space for the local matrices */
X    x = mat_new(m, 1);
X    diff = mat_new(m, 1);
X
X    /* Iterate up to max_it times */
X    for (k = 0; k < max_it; k++)
X    {
X        for (i = 0; i < m; i++)
X        {
X            /* Calculate the new xi */
X            sum1 = 0;
X            for (j = 0; j < i; j++)
X                sum1 += a[i][j]*x[j][0];
X            sum2 = 0;
X            for (j = i+1; j < m; j++)
X                sum2 += a[i][j]*xo[j][0];
X            x[i][0] = (1.0 - omega)*xo[i][0] + omega*(-sum1-sum2+a[i][m])/a[i][i];
X
X        }
X
X#ifdef DEBUG
X        printf("Next approximation:\n");
X        mat_print("%10.6g ", x, m, 1);
X#endif
X
X        /* Check for stopping criteria */
X        mat_add(diff, x, xo, m, 1, (double)-1.0);
X        if (norm_2(diff, m, 1) < error)
X        {
X            /* Copy the new x into the xo matrix */
X            for (i = 0; i < m; i++)
X                xo[i][0] = x[i][0];
X            /* Values approximated successfully */
X            mat_free(x, m, 1);
X            mat_free(diff, m, 1);
X            return(OK);
X        }
X
X        /* Copy the new x into the xo matrix */
X        for (i = 0; i < m; i++)
X            xo[i][0] = x[i][0];
X    }
X
X    /* Maximum iterations exceeded */
X    mat_free(x, m, 1);
X    mat_free(diff, m, 1);
X    return(MAX_ITERATIONS);
X}
/*EOF
ls -l mat_SOR.c
sed 's/^X//' > mat_add.c << '/*EOF'
X/*
X**  mat_add
X**
X**      Add two matrices.
X**
X**  Input:
X**      a, b    -   the two matrices to add.
X**      m, n    -   the size of the matrices.
X**      scale   -   scale b before add.
X**
X**  Output:
X**      sum     -   the sum of two matrices.
X*/
X
Xmat_add(sum, a, b, m, n, scale)
Xdouble  **sum, **a, **b;
Xint     m, n;
Xdouble  scale;
X{
X    int     i, j;
X
X    for (i = 0; i < m; i++)
X        for (j = 0; j < n; j++)
X            sum[i][j] = a[i][j] + scale * b[i][j];
X}
/*EOF
ls -l mat_add.c
sed 's/^X//' > mat_backward.c << '/*EOF'
X/*
X**  mat_backward
X**
X**      Do backward substitution on a upper triangular matrix.
X**
X**  Input:
X**      matrix  -   matrix to do backward substitiution.
X**      m       -   number of unknowns.
X**
X**  Output:
X**      matrix  -   The reduced matrix.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
X#include    "matrix.h"
X
Xmat_backward(matrix, m)
Xdouble  **matrix;
Xint     m;
X{
X    int     i, j;
X
X    for (i = m-1; i > 0; i--)
X    {
X
X        /* Scale the row so the first element is 1 */
X        /* This row should have been reduced to all zeros except two */
X#ifdef DEBUG
X        printf("(matrix[%d]) <-- (%g*matrix[%d])\n", i, 1.0/matrix[i][i], i);
X#endif
X        matrix[i][m] /= matrix[i][i];
X        matrix[i][i] = (double)1.0;
X#ifdef DEBUG
X        mat_print("%10.6g ",matrix, m, m+1);
X#endif
X
X        for (j = 0; j < i; j++)
X        {
X
X            /* subtract the row from every one above */
X#ifdef DEBUG
X            printf("(matrix[%d] - %g*matrix[%d]) --> (matrix[%d])\n", j, matrix[j][i], i, j);
X#endif
X            matrix[j][m] += -matrix[j][i] * matrix[i][m];
X            matrix[j][i] = (double)0.0;
X
X        }
X
X#ifdef DEBUG
X        mat_print("%10.6g ",matrix, m, m+1);
X#endif
X    }
X
X    /* Scale the top row */
X#ifdef DEBUG
X    printf("(matrix[%d]) <-- (%g*matrix[%d])\n", 0, 1.0/matrix[0][0], 0);
X#endif
X    matrix[0][m] /= matrix[0][0];
X    matrix[0][0] = (double)1.0;
X#ifdef DEBUG
X    mat_print("%10.6g ",matrix, m, m+1);
X#endif
X
X    return(OK);
X}
/*EOF
ls -l mat_backward.c
sed 's/^X//' > mat_copy.c << '/*EOF'
X/*
X**  mat_copy
X**
X**      copy a smaller matrix into a matrix (usually augmented)
X**
X**  Input:
X**      old     -   small matrix to copy.
X**      m, n    -   size of Old (mxn).
X**      row, col -  row and column to start copying to.
X**
X**  Output:
X**      new     -   the matrix being copied into.
X*/
X
Xmat_copy(new, old, m, n, row, col)
Xdouble  **new, **old;
Xint     m, n, row, col;
X{
X    int     i, j;
X
X    for (i = 0; i < m; i++)
X        for (j = 0; j < n; j++)
X            new[row+i][col+j] = old[i][j];
X}
/*EOF
ls -l mat_copy.c
sed 's/^X//' > mat_free.c << '/*EOF'
X/*
X**  mat_free
X**
X**  Free the space used by a matrix.
X**
X**  Input:
X**      matrix  -   The matrix.
X**      m, n    -   The size of the matrix.
X**
X**  Output:
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
Xmat_free(matrix, m, n)
Xdouble  **matrix;
Xint     m, n;
X{
X    int i;
X
X    for (i=0; i<m; i++)
X        free(matrix[i]);
X    free(matrix);
X}
/*EOF
ls -l mat_free.c
sed 's/^X//' > mat_gauss.c << '/*EOF'
X/*
X**  mat_gauss
X**
X**      gaussian elimination of a matrix using partial pivoting and
X**      backward substitiution.
X**
X**  Input:
X**      matrix  -   The matrix to reduce.
X**      m       -   number of unknowns.
X**
X**  Output:
X**      matrix  -   The reduced matrix.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**  Reference:  Numerical Analysis
X**              Burden, Faires, and Reynolds
X**              pages 268-269
X**
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xmat_gauss(matrix, m)
Xdouble  **matrix;
Xint     m;
X{
X    int     i, p, best_p;
X    double  scale;
X
X#ifdef DEBUG
X            printf("Solving:\n");
X            mat_print("%10.6g ", matrix, m, m+1);
X#endif
X    for (i = 0; i < (m-1); i++)
X    {
X
X        /* Find the maximum first row element and swap rows */
X        best_p = i;
X        for (p = (i+1); p < m; p++)
X            if (_ABS(matrix[p][i]) > _ABS(matrix[best_p][i]))
X                best_p = p;
X        if (matrix[best_p][i] == (double)0.0)
X            return(NON_UNIQUE);
X        if (best_p != i)
X        {
X            row_swap(matrix, i, best_p);
X#ifdef DEBUG
X            printf("(matrix[%d]) <--> (matrix[%d])\n", i, best_p);
X            mat_print("%10.6g ", matrix, m, m+1);
X#endif
X        }
X
X        /* Do Gaussian elmination to eliminate the lower triangle */
X        for (p = (i+1); p < m; p++)
X        {
X            scale = matrix[p][i]/matrix[i][i];
X            row_add(matrix, p, i, m+1, -scale);
X            /* eliminate roundoff error.  */
X            matrix[p][i] = 0;
X#ifdef DEBUG
X            printf("(matrix[%d] - %g*matrix[%d]) --> (matrix[%d])\n", p, scale, i, p);
X#endif
X        }
X#ifdef DEBUG
X        mat_print("%10.6g ", matrix, m, m+1);
X#endif
X    }
X    if (matrix[m-1][m-1] == 0)
X        return(NON_UNIQUE);
X
X    /* Do backward substitiution */
X    mat_backward(matrix, m);
X
X    return(OK);
X}
/*EOF
ls -l mat_gauss.c
sed 's/^X//' > mat_least.c << '/*EOF'
X/*
X**  mat_least
X**
X**      Least squares appoximating polynomial of degree n.
X**
X**  Input:
X**      x       -   nx1 matrix of x data points.
X**      y       -   nx1 matrix of y data points.
X**      n       -   number of data points.
X**      degree  -   degree of the approximating polynomial.
X**
X**  Output:
X**      coef    -   degreex1 matrix of polynomial coefficients.
X**      resid   -   degreex1 matrix of residuals.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xmat_least(x, y, n, degree, coef, resid)
Xdouble  **x, **y;
Xint     n, degree;
Xdouble  **coef, **resid;
X{
X    double  **A;        /* matrix of the x^i for i=0..degree, j=1..n */
X    double  **At;       /* Transpose of A */
X    double  **AtA;      /* Transpose of A premultiplies A */
X    double  **Aty;      /* Transpose of A premultiplies y */
X    double  **Aug;      /* Augmneted matrix [AtA|Aty] */
X    double  **Acoef;    /* A premultiplies coef */
X
X    double  xtemp;
X    int     i,j;
X    int     code;
X
X    extern  double  **mat_new();
X
X    /*  Build matrix A which is:
X        [ 1  x0 x0^2 ... x0^n ]
X        ...
X        [ 1  xi xi^2 ... xi^n ]
X    */
X    degree++;
X    A = mat_new(n, degree);
X    for(j=0; j<n; j++)
X    {
X        xtemp = 1.0;
X        for (i=0; i<degree; i++)
X        {
X            A[j][i] = xtemp;
X            xtemp *= x[j][0];
X        }
X    }
X
X#ifdef  DEBUG
X    printf("\nA matrix:\n");
X    mat_print("%- 010.6g ", A, n, degree);
X#endif
X
X    /* Calculate the transpose of A (refered to as At) */
X    At = mat_new(degree, n);
X    mat_trans(At, A, n, degree);
X
X    /* Calculate At premultiply A (AtA) */
X    AtA = mat_new(degree, degree);
X    mat_mult(AtA, At, A, degree, n, degree);
X
X#ifdef  DEBUG
X    printf("\nAtA matrix:\n");
X    mat_print("%- 010.6g ", AtA, degree, degree);
X#endif
X
X    /* Calculate At premultiply y (Aty) */
X    Aty = mat_new(degree, 1);
X    mat_mult(Aty, At, y, degree, n, 1);
X
X#ifdef  DEBUG
X    printf("\nAty matrix:\n");
X    mat_print("%- 010.6g ", Aty, degree, 1);
X#endif
X
X    /* Make an augmented matrix to solve AtA(coef) = Aty */
X    Aug = mat_new(degree, degree+1);
X    mat_copy(Aug, AtA, degree, degree, 0, 0);
X    mat_copy(Aug, Aty, degree, 1, 0, degree);
X
X    /* Call the routine to solve the augmented matrix */
X    code = mat_gauss(Aug, degree);
X
X    if(code == OK)
X    {
X        /* Remove the solution from the matrix */
X        mat_remove(coef, degree, 1, Aug, degree, degree+1, 0, degree);
X
X        /* Calculate A premultiply coef (Acoef) */
X        Acoef = mat_new(n, 1);
X        mat_mult(Acoef, A, coef, n, degree, 1);
X
X        /* Calculate the residuals using: y - coef = resid */
X        mat_add(resid, y, Acoef, n, 1, (double)-1.0);
X    }
X
X    /* Free up the temporary matrices used in this function */
X    mat_free(A, n, degree);
X    mat_free(At, degree, n);
X    mat_free(AtA, degree, degree);
X    mat_free(Aty, degree, 1);
X    mat_free(Aug, degree, degree+1);
X    mat_free(Acoef, n, 1);
X
X    return(code);
X}
/*EOF
ls -l mat_least.c
sed 's/^X//' > mat_mult.c << '/*EOF'
X/*
X**  mat_mult
X**
X**      Multiply two matrices.
X**
X**  Input:
X**      a, b    -   the two matrices to multiply.
X**      m, n, p -   the size of the matrices. (mxn and nxp)
X**
X**  Output:
X**      prod    -   the product of two matrices.
X*/
X
Xmat_mult(prod, a, b, m, n, p)
Xdouble  **prod, **a, **b;
Xint     m, n, p;
X{
X    int     i, j, k;
X
X    for (i = 0; i < m; i++)
X        for (j = 0; j < p; j++)
X        {
X            prod[i][j] = 0;
X            for (k = 0; k < n; k++)
X                prod[i][j] += a[i][k] * b[k][j];
X        }
X}
/*EOF
ls -l mat_mult.c
sed 's/^X//' > mat_new.c << '/*EOF'
X/*
X**  mat_new
X**
X**  Create a new mxn matrix.
X**
X**  Input:
X**      m, n    -   The size of the matrix.
X**
X**  Output:
X**      matrix  -   The matrix.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
Xdouble  **mat_new(m, n)
Xint     m, n;
X{
X    double  **matrix;
X    int i;
X
X    matrix = (double **)malloc(sizeof(double *) * m);
X    for (i=0; i<m; i++)
X        matrix[i] = (double *)calloc(n, sizeof(double));
X    return(matrix);
X}
/*EOF
ls -l mat_new.c
sed 's/^X//' > mat_print.c << '/*EOF'
X/*
X**  mat_print
X**
X**      print the matrix
X**
X**  Input:
X**      format  -   format of the numbers.
X**      matrix  -   matrix with size of mxn.
X**      m, n    -   size of matrix.
X**
X*/
X
Xmat_print(format, matrix, m, n)
Xchar    *format;
Xdouble  **matrix;
Xint     m, n;
X{
X    int     i, j;
X
X    for(i = 0; i < m; i++)
X    {
X        for (j = 0; j < n; j++)
X            printf(format, matrix[i][j]);
X        printf("\n");
X    }
X}
/*EOF
ls -l mat_print.c
sed 's/^X//' > mat_remove.c << '/*EOF'
X/*
X**  mat_remove
X**
X**      Remove a part of a matrix and put it into new.
X**
X**  Input:
X**      m_new, n_new    -   size of new (mxn).
X**      old             -   small matrix to copy.
X**      m_old, n_old    -   size of Old (mxn).
X**      row, col        -   row and column to start copying from.
X**
X**  Output:
X**      new             -   the matrix being copied into.
X*/
X
Xmat_remove(new, m_new, n_new, old, m_old, n_old, row, col)
Xdouble  **new, **old;
Xint     m_new, n_new, m_old, n_old, row, col;
X{
X    int     i, j;
X
X    for (i = 0; i < m_new; i++)
X        for (j = 0; j < n_new; j++)
X            new[i][j] = old[row+i][col+j];
X}
/*EOF
ls -l mat_remove.c
sed 's/^X//' > mat_scale.c << '/*EOF'
X/*
X**  mat_scale
X**
X**      Scale a matrix.
X**
X**  Input:
X**      matrix  -   matrix to scale.
X**      m, n    -   size of matrix (mxn).
X**      scale   -   scaling factor.
X**
X**  Output:
X**      new     -   new matrix that has been scaled.
X**
X*/
X
Xmat_scale(new, matrix, m, n, scale)
Xdouble  **new, **matrix;
Xint     m, n;
Xdouble  scale;
X{
X    int     i, j;
X
X    for (i = 0; i < m; i++)
X        for (j = 0; j < n; j++)
X            new[i][j] = scale * matrix[i][j];
X}
/*EOF
ls -l mat_scale.c
sed 's/^X//' > mat_scan.c << '/*EOF'
X/*
X**  mat_scan
X**
X**      Read in an mxn matrix.
X**
X**  Input:
X**      Format  -   format to read the values in.
X**      matrix  -   an mxn matrix.
X**      m, n    -   the size of the matrix.
X**
X**  Output:
X**      matrix  -   the matrix with all the values set.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
Xmat_scan(format, matrix, m, n)
Xchar    *format;
Xdouble  **matrix;
Xint     m, n;
X{
X    int     i, j;
X
X    for(i = 0; i < m; i++)
X        for (j = 0; j < n; j++)
X            scanf(format, &(matrix[i][j]));
X}
/*EOF
ls -l mat_scan.c
sed 's/^X//' > mat_trans.c << '/*EOF'
X/*
X**  mat_trans
X**
X**      Transpose a matrix.
X**
X**  Input:
X**      a       -   the matrix to transpose
X**      m, n    -   the size of the matrix. (mxn)
X**
X**  Output:
X**      at      -   the transpose of a.
X*/
X
Xmat_trans(at, a, m, n)
Xdouble  **at, **a;
Xint     m, n;
X{
X    int     i, j;
X
X    for (i = 0; i < m; i++)
X        for (j = 0; j < n; j++)
X            at[j][i] = a[i][j];
X}
/*EOF
ls -l mat_trans.c
sed 's/^X//' > mat_w_least.c << '/*EOF'
X/*
X**  mat_w_least
X**
X**      Weighted least squares appoximating polynomial of degree n.
X**
X**  Input:
X**      x       -   nx1 matrix of x data points.
X**      y       -   nx1 matrix of y data points.
X**      w       -   nxn matrix of w weights.
X**      n       -   number of data points.
X**      degree  -   degree of the approximating polynomial.
X**
X**  Output:
X**      coef    -   degreex1 matrix of polynomial coefficients.
X**      resid   -   degreex1 matrix of residuals.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xmat_w_least(x, y, w, n, degree, coef, resid)
Xdouble  **x, **y, **w;
Xint     n, degree;
Xdouble  **coef, **resid;
X{
X    double  **A;        /* matrix of the x^i for i=0..degree, j=1..n */
X    double  **At;       /* Transpose of A */
X    double  **Atw;      /* Transpose of A premultiplies w */
X    double  **AtwA;     /* Atw premultiplies A */
X    double  **Atwy;     /* Atw premultiplies y */
X    double  **Aug;      /* Augmneted matrix [AtwA|Atwy] */
X    double  **Acoef;    /* A premultiplies coef */
X
X    double  xtemp;
X    int     i,j;
X    int     code;
X
X    extern  double  **mat_new();
X
X    /*  Build matrix A which is:
X        [ 1  x0 x0^2 ... x0^n ]
X        ...
X        [ 1  xi xi^2 ... xi^n ]
X    */
X    degree++;
X    A = mat_new(n, degree);
X    for(j=0; j<n; j++)
X    {
X        xtemp = 1.0;
X        for (i=0; i<degree; i++)
X        {
X            A[j][i] = xtemp;
X            xtemp *= x[j][0];
X        }
X    }
X
X#ifdef  DEBUG
X    printf("\nA matrix:\n");
X    mat_print("%- 010.6g ", A, n, degree);
X#endif
X
X    /* Calculate the transpose of A (refered to as At) */
X    At = mat_new(degree, n);
X    mat_trans(At, A, n, degree);
X
X#ifdef  DEBUG
X    printf("\nAt matrix:\n");
X    mat_print("%- 010.6g ", At, degree, n);
X#endif
X
X    /* Calculate At premultiply w (Atw) */
X    Atw = mat_new(degree, n);
X    mat_mult(Atw, At, w, degree, n, n);
X
X#ifdef  DEBUG
X    printf("\nAtw matrix:\n");
X    mat_print("%- 010.6g ", Atw, degree, n);
X#endif
X
X    /* Calculate AtwA */
X    AtwA = mat_new(degree, degree);
X    mat_mult(AtwA, Atw, A, degree, n, degree);
X
X#ifdef  DEBUG
X    printf("\nAtwA matrix:\n");
X    mat_print("%- 010.6g ", AtwA, degree, degree);
X#endif
X
X    /* Calculate At premultiply y (Atwy) */
X    Atwy = mat_new(degree, 1);
X    mat_mult(Atwy, Atw, y, degree, n, 1);
X
X#ifdef  DEBUG
X    printf("\nAtwy matrix:\n");
X    mat_print("%- 010.6g ", Atwy, degree, 1);
X#endif
X
X    /* Make an augmented matrix to solve AtwA(coef) = Atwy */
X    Aug = mat_new(degree, degree+1);
X    mat_copy(Aug, AtwA, degree, degree, 0, 0);
X    mat_copy(Aug, Atwy, degree, 1, 0, degree);
X
X    /* Call the routine to solve the augmented matrix */
X    code = mat_gauss(Aug, degree);
X
X    if(code == OK)
X    {
X        /* Remove the solution from the matrix */
X        mat_remove(coef, degree, 1, Aug, degree, degree+1, 0, degree);
X
X        /* Calculate A premultiply coef (Acoef) */
X        Acoef = mat_new(n, 1);
X        mat_mult(Acoef, A, coef, n, degree, 1);
X
X        /* Calculate the residuals using: y - coef = resid */
X        mat_add(resid, y, Acoef, n, 1, (double)-1.0);
X    }
X
X    /* Free up the temporary matrices used in this function */
X    mat_free(A, n, degree);
X    mat_free(At, degree, n);
X    mat_free(Atw, degree, n);
X    mat_free(AtwA, degree, degree);
X    mat_free(Atwy, degree, 1);
X    mat_free(Aug, degree, degree+1);
X    mat_free(Acoef, n, 1);
X
X    return(code);
X}
/*EOF
ls -l mat_w_least.c
sed 's/^X//' > matrix.h << '/*EOF'
X#define OK  0               /* No error return value */
X#define NON_UNIQUE  1       /* Non-unique answer to a reduced matrix */
X#define MAX_ITERATIONS  2   /* Maximum nuber of iterations excedded */
X#define FALSE 0
X#define TRUE 1
/*EOF
ls -l matrix.h
sed 's/^X//' > mult.c << '/*EOF'
X/*
X**  mult
X**
X**      Program to multiply two matrices.
X**
X**  Author:     Paul Schmidt
X**  Date:       February 1986
X**
X*/
X
X#include    <stdio.h>
X
Xmain()
X{
X    extern  double  **mat_new();
X
X    double  **a, **b, **prod;
X    int     m, n, m1, n1;
X
X    fprintf(stderr,"Input size: ");
X    scanf("%d %d", &m, &n);
X    a = mat_new(m, n);
X    fprintf(stderr,"Input matrix: \n");
X    mat_scan("%g",a , m, n);
X    fprintf(stderr,"Input size: ");
X    scanf("%d %d", &m1, &n1);
X    if (n != m1)
X    {
X        mat_free(a, m, n);
X        fprintf(stderr,"mult error: Matrices not the correct size\n");
X        exit(-1);
X    }
X    b = mat_new(m1, n1);
X    fprintf(stderr,"Input matrix: \n");
X    mat_scan("%g", b, m1, n1);
X    prod = mat_new(m, n1);
X    mat_mult(prod, a, b, m, n, n1);
X    mat_free(a, m, n);
X    mat_free(b, m1, n1);
X    fprintf(stderr,"Matrix product:\n");
X    printf("%d %d\n", m, n1);
X    mat_print("%10.6g ", prod, m, n1);
X    mat_free(prod, m, n1);
X    exit(0);
X}
/*EOF
ls -l mult.c
sed 's/^X//' > norm_2.c << '/*EOF'
X/*
X**  norm_2
X**
X**      Find the l2 norm of a matrix.
X**
X**  Input:
X**      A       -   nxm matrix to calculate norm
X**      n, m    -   size of the matrix.
X**
X**  Output:
X**      value of the norm.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 March 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xdouble  norm_2(a, m, n)
Xdouble  **a;
Xint     m, n;
X{
X    int     i, j;
X    double  sum;
X
X    if (n != 1)
X    {
X        fprintf("norm_2 called with n > 1.  Not implemented for more\n");
X        return((double)0.0);
X    }
X    sum = 0.0;
X    for (i = 0; i < m; i++)
X    {
X        sum += a[i][0]*a[i][0];
X    }
X    return(sqrt(sum));
X}
/*EOF
ls -l norm_2.c
sed 's/^X//' > norm_inf.c << '/*EOF'
X/*
X**  norm_inf
X**
X**      Find the infinity norm of a matrix.
X**
X**  Input:
X**      A       -   nxm matrix to calculate norm
X**      n, m    -   size of the matrix.
X**
X**  Output:
X**      value of the norm.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 March 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X*/
X
X#include <math.h>
X#include "matrix.h"
X
Xdouble  norm_inf(a, m, n)
Xdouble  **a;
Xint     m, n;
X{
X    int     i, j;
X    double  sum, max;
X
X    max = 0.0;
X    for (i = 0; i < m; i++)
X    {
X        sum = 0.0;
X        for (j = 0; j < n; j++)
X            sum += _ABS(a[i][j]);
X        if (sum > max)
X            max = sum;
X    }
X#ifdef DEBUG
X    printf("The infinity norm of:\n");
X    mat_print("%10.6g ", a, m, n);
X    printf("is:  %g\n", max);
X#endif DEBUG
X    return(max);
X}
/*EOF
ls -l norm_inf.c
sed 's/^X//' > row_add.c << '/*EOF'
X/*
X**  row_add
X**
X**      Add a scaled row to a row an replace that row.
X**
X**  Input:
X**      matrix  -   matrix to operate on.
X**      i       -   row i to replace.
X**      j       -   row j to scale and add to row i.
X**      cols    -   number of columns.
X**      scale   -   scale of row j.
X**
X**  Output:
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
Xrow_add(matrix, i, j, cols, scale)
Xdouble  **matrix;
Xint     i, j, cols;
Xdouble  scale;
X{
X    int     index;
X
X    for (index = 0; index < cols; index++)
X        matrix[i][index] += scale * matrix[j][index];
X}
/*EOF
ls -l row_add.c
sed 's/^X//' > row_scale.c << '/*EOF'
X/*
X**  row_scale
X**
X**  Routine to scale a row in a matrix.
X**
X**  Input:
X**      matrix  -   The matrix to operate on.
X**      row     -   row to scale.
X**      cols    -   Number of columns.
X**      scale   -   Scale factor.
X**
X**  Output:
X**      matrix  The altered matrix.
X**
X*/
X
X
Xrow_scale(matrix, row, cols, scale)
Xdouble  **matrix;
Xint     row, cols;
Xdouble  scale;
X{
X    int     i;
X
X    for (i = 0; i < cols; i++)
X        matrix[row][i] *= scale;
X}
/*EOF
ls -l row_scale.c
sed 's/^X//' > row_swap.c << '/*EOF'
X/*
X**  row_swap
X**
X**  Routine to swap two rows in a matrix.
X**
X**  Input:
X**      matrix  The matrix to operate on.
X**      i, j    Rows to swap.
X**
X**  Output:
X**      matrix  The altered matrix.
X**
X**  Author:     Paul Schmidt
X**  Date:       5 February 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X**
X*/
X
X
Xrow_swap(matrix, i, j)
Xdouble  **matrix;
Xint     i, j;
X{
X    double  *temp;
X
X    temp = matrix[i];
X    matrix[i] = matrix[j];
X    matrix[j] = temp;
X}
/*EOF
ls -l row_swap.c
sed 's/^X//' > w_least.c << '/*EOF'
X/*
X**  w_least
X**
X**      Program to approximate a polynomial by using weighted least squares.
X**
X**  Author:     Paul Schmidt
X**  Date:       19 March 1986
X**  Class:      Numerical & Statistical Methods
X**  Number:     222-4267-201
X**  Instructor: Jerry Sayers
X*/
X
X#include    <stdio.h>
X#include    "matrix.h"
X
Xmain()
X{
X    double  **x, **y, **w, **coef, **resid;
X    int     number, degree, i;
X
X    extern  double  **mat_new();
X
X    fprintf(stderr, "Program to calculate a polynomial using weighted least squares.\n");
X    fprintf(stderr, "What is the degree of the polynomial?  ");
X    scanf("%d", &degree);
X    fprintf(stderr, "How many data points?  ");
X    scanf("%d", &number);
X    x = mat_new(number, 1);
X    y = mat_new(number, 1);
X    w = mat_new(number, number);
X    fprintf(stderr, "Input data points (x y):\n");
X    for (i=0; i<number; i++)
X    {
X        scanf("%g", &(x[i][0]));
X        scanf("%g", &(y[i][0]));
X    }
X    fprintf(stderr, "Input weights:\n");
X    for (i=0; i<number; i++)
X    {
X        scanf("%g", &(w[i][i]));
X    }
X
X    /* Echo the data points */
X    printf("%-10s %-10s %-10s\n", "  X  ", "  Y  ", " WEIGHT ");
X    for (i=0; i<number; i++)
X        printf("%- 010.6g %- 010.6g %- 010.6g\n", x[i][0], y[i][0], w[i][i]);
X
X    /* Allocate space for the coefficients and residuals and call the
X        least squares routine. */
X    resid = mat_new(number, 1);
X    coef = mat_new(degree+1, 1);
X    if (mat_w_least(x, y, w, number, degree, coef, resid) != OK)
X    {
X        fprintf(stderr, "Least sqaure calculation failed\n");
X        exit(-1);
X    }
X
X    printf("\nThe approximating polynomial:\n");
X    for (i=0; i<=degree; i++)
X    {
X        if (i==0)
X            printf("Y = %g ", coef[i][0]);
X        if (i==1)
X            printf("%gX ", coef[i][0]);
X        if (i>1)
X            printf("%gX^%d ", coef[i][0], i);
X        if (i != degree)
X            printf("+ ");
X    }
X    printf("\n");
X
X    printf("\nThe residuals for the data points are:\n");
X    mat_print("%- 010.6g", resid, number, 1);
X
X    /* Free the matrices */
X    mat_free(x, number, 1);
X    mat_free(y, number, 1);
X    mat_free(w, number, number);
X    mat_free(coef, degree+1, 1);
X    mat_free(resid, number,1);
X
X    /* Exit the program successfully */
X    exit(0);
X}
/*EOF
ls -l w_least.c
exit