









I took an advanced graphics class in the spring quarter of 1999 at Auburn University under Professor Kai Chang. We used the Open Graphics Library in the languages C/C++. I later modified my class project into a Mercator map projection application. I have attached some screen shots from the Mercator projection application.
/*
Author: Pate Williams (c) 1997
"Algorithm 2.3.2 (Image of a Matrix). Given an
m by n matrix M = (m[i][i]) with 1 <= i <= m and
1 <= j <= n having coefficients in the field K,
this algorithm outputs a basis of the image of
M, i. e. vector space spanned by the columns of
M." -Henri Cohen- See "A Course in Computational
Algebraic Number Theory" by Henri Cohen pages
58-59. We specialize the code to the field Zp.
*/
#include <stdio.h>
#include <stdlib.h>
long** create_matrix(long m, long n)
{
long i, ** matrix = (long**)calloc(m, sizeof(long*));
if (!matrix) {
fprintf(stderr, "fatal error\ninsufficient memory\n");
fprintf(stderr, "from create_matrix\n");
exit(1);
}
for (i = 0; i < m; i++) {
matrix[i] = (long*)calloc(n, sizeof(long));
if (!matrix[i]) {
fprintf(stderr, "fatal error\ninsufficient memory\n");
fprintf(stderr, "from create_matrix\n");
exit(1);
}
}
return matrix;
}
void delete_matrix(long m, long** matrix)
{
long i;
for (i = 0; i < m; i++) free(matrix[i]);
free(matrix);
}
void Euclid_extended(long a, long b, long* u,
long* v, long* d)
{
long q, t1, t3, v1, v3;
*u = 1, * d = a;
if (b == 0) {
*v = 0;
return;
}
v1 = 0, v3 = b;
#ifdef DEBUG
printf("----------------------------------\n");
printf(" q t3 *u *d t1 v1 v3\n");
printf("----------------------------------\n");
#endif
while (v3 != 0) {
q = *d / v3;
t3 = *d - q * v3;
t1 = *u - q * v1;
*u = v1, * d = v3;
#ifdef DEBUG
printf("%4ld %4ld %4ld ", q, t3, *u);
printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3);
#endif
v1 = t1, v3 = t3;
}
*v = (*d - a * *u) / b;
#ifdef DEBUG
printf("----------------------------------\n");
#endif
}
long inv(long number, long modulus)
{
long d, u, v;
Euclid_extended(number, modulus, &u, &v, &d);
if (d == 1) return u;
return 0;
}
void image(long m, long n, long p,
long** M, long** X, long* r)
{
int found;
long D, i, j, k, s;
long* c = (long*)calloc(m, sizeof(long));
long* d = (long*)calloc(n, sizeof(long));
long** N = create_matrix(m, n);
if (!c || !d) {
fprintf(stderr, "fatal error\ninsufficient memory\n");
fprintf(stderr, "from kernel\n");
exit(1);
}
for (i = 0; i < m; i++) {
c[i] = -1;
for (j = 0; j < n; j++) N[i][j] = M[i][j];
}
*r = 0;
for (k = 0; k < n; k++) {
found = 0, j = 0;
while (!found && j < m) {
found = M[j][k] != 0 && c[j] == -1;
if (!found) j++;
}
if (found) {
D = p - inv(M[j][k], p);
M[j][k] = p - 1;
for (s = k + 1; s < n; s++)
M[j][s] = (D * M[j][s]) % p;
for (i = 0; i < m; i++) {
if (i != j) {
D = M[i][k];
M[i][k] = 0;
for (s = k + 1; s < n; s++) {
M[i][s] = (M[i][s] + D * M[j][s]) % p;
if (M[i][s] < 0) M[i][s] += p;
}
}
}
c[j] = k;
d[k] = j;
}
else {
*r = *r + 1;
d[k] = -1;
}
}
for (j = 0; j < m; j++) {
if (c[j] != -1) {
for (i = 0; i < n; i++) {
if (i < m) X[i][j] = N[i][c[j]];
else X[i][j] = 0;
}
}
}
delete_matrix(m, N);
free(c);
free(d);
}
void print_matrix(long m, long n, long** a)
{
long i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++)
printf("%2ld ", a[i][j]);
printf("\n");
}
}
int main(void)
{
long i, j, m = 8, n = 8, p = 13, r;
long a[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0},
{2, 0, 7, 11, 10, 12, 5, 11},
{3, 6, 3, 3, 0, 4, 7, 2},
{4, 3, 6, 4, 1, 6, 2, 3},
{2, 11, 8, 8, 2, 1, 3, 11},
{6, 11, 8, 6, 2, 6, 10, 9},
{5, 11, 7, 10, 0, 11, 6, 12},
{3, 3, 12, 5, 0, 11, 9, 11} };
long** M = create_matrix(m, n);
long** X = create_matrix(n, n);
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
M[i][j] = a[j][i];
printf("the original matrix is as follows:\n");
print_matrix(m, n, M);
image(m, n, p, M, X, &r);
printf("the image of the matrix is as follows:\n");
print_matrix(n, n - r, X);
printf("the rank of the matrix is: %ld\n", n - r);
delete_matrix(m, M);
delete_matrix(n, X);
return 0;
}

I took up plastic scale modeling again in about 2017 at the age of around 64. Here is a list of my models and some notes about their construction. All of my relatively modern models are by Revell:
If you have plenty of cash and patience, you can use spray paint. I prefer the somewhat inexpensive brush painting.
/*
Author: Pate Williams (c) 1997
"Algorithm 2.3.5 (Inverse Image Matrix). Let M be
an m by n matrix and V be an m by r matrix, where
n <= m. This algorithm either outputs a message
saying that some column vector of V is not in the
image of M, or outputs an n by r matrix X such
that V = MX." -Henri Cohen- See "A Course in Com-
putational Algebraic Number Theory" by Henri
Cohen pages 60-61. We specialize to the field Q.
*/
#include <stdio.h>
#include <stdlib.h>
double** create_matrix(long m, long n)
{
double** matrix = (double**)calloc(m, sizeof(double*));
long i;
if (!matrix) {
fprintf(stderr, "fatal error\ninsufficient memory\n");
fprintf(stderr, "from create_matrix\n");
exit(1);
}
for (i = 0; i < m; i++) {
matrix[i] = (double*)calloc(n, sizeof(double));
if (!matrix[i]) {
fprintf(stderr, "fatal error\ninsufficient memory\n");
fprintf(stderr, "from create_matrix\n");
exit(1);
}
}
return matrix;
}
void delete_matrix(long m, double** matrix)
{
long i;
for (i = 0; i < m; i++) free(matrix[i]);
free(matrix);
}
void inverse_image_matrix(long m, long n, long r,
double** M, double** V,
double** X)
{
double ck, d, sum, t;
double** B = create_matrix(m, r);
int found;
long i, j, k, l;
for (i = 0; i < m; i++)
for (j = 0; j < r; j++)
B[i][j] = V[i][j];
for (j = 0; j < n; j++) {
found = 0, i = j;
while (!found && i < m) {
found = M[i][j] != 0;
if (!found) i++;
}
if (!found) {
fprintf(stderr, "fatal error\nnot linearly independent\n");
fprintf(stderr, "from inverse_image_matrix\n");
exit(1);
}
if (i > j) {
for (l = 0; l < n; l++)
t = M[i][l], M[i][l] = M[j][l], M[j][l] = t;
for (l = 0; l < r; l++)
t = B[i][l], B[i][l] = B[j][l], B[j][l] = t;
}
d = 1.0 / M[j][j];
for (k = j + 1; k < m; k++) {
ck = d * M[k][j];
for (l = j + 1; l < n; l++)
M[k][l] -= ck * M[j][l];
for (l = 0; l < r; l++)
B[k][l] -= ck * B[j][l];
}
}
for (i = n - 1; i >= 0; i--) {
for (k = 0; k < r; k++) {
sum = 0;
for (j = i + 1; j < n; j++)
sum += M[i][j] * X[j][k];
X[i][k] = (B[i][k] - sum) / M[i][i];
}
}
for (k = n + 1; k < m; k++) {
for (j = 0; j < r; j++) {
sum = 0;
for (i = 0; i < n; i++)
sum += M[k][i] * X[i][j];
if (sum != B[k][j]) {
fprintf(stderr, "fatal error\ncolumn not in image\n");
fprintf(stderr, "from inverse_image_matrix\n");
exit(1);
}
}
}
delete_matrix(m, B);
}
void matrix_multiply(long m, long n, long r,
double** a, double** b,
double** c)
/* c = a * b */
{
double sum;
long i, j, k;
for (i = 0; i < m; i++) {
for (j = 0; j < r; j++) {
sum = 0.0;
for (k = 0; k < n; k++)
sum += a[i][k] * b[k][j];
c[i][j] = sum;
}
}
}
void print_matrix(long m, long n, double** a)
{
long i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++)
printf("%+10.6lf ", a[i][j]);
printf("\n");
}
}
int main(void)
{
long i, j, m = 4, n = 4, r = 4;
double** c = create_matrix(m, n);
double** M = create_matrix(m, n);
double** V = create_matrix(m, r);
double** X = create_matrix(n, r);
for (i = 0; i < m; i++) {
c[i][i] = M[i][i] = 2.0;
if (i > 0)
c[i][i - 1] = M[i][i - 1] = -1.0;
if (i < m - 1)
c[i][i + 1] = M[i][i + 1] = -1.0;
}
for (i = 0; i < m; i++)
for (j = 0; j < r; j++)
V[i][j] = i + j + 1;
printf("M is as follows:\n");
print_matrix(m, n, M);
printf("V is as follows:\n");
print_matrix(m, r, V);
inverse_image_matrix(m, n, r, M, V, X);
printf("X is as follows:\n");
print_matrix(n, r, X);
matrix_multiply(m, n, r, c, X, M);
printf("MX is as follows:\n");
print_matrix(m, r, M);
delete_matrix(m, c);
delete_matrix(m, M);
delete_matrix(m, V);
delete_matrix(n, X);
return 0;
}

Back in the year 1999 I studied Constraint Satisfaction Problems (CSPs) which is a branch of the computer science discipline artificial intelligence (AI). I took a course in Artificial Intelligence and then a Machine Learning course both under Professor Gerry V. Dozier at Auburn University in the Winter and Spring Quarters of 1999. Professor Dozier was my Master of Software Engineering degree advisor. The N-Queens Problem is a constraint satisfaction problem within the setting of a N-by-N chessboard with the queens arranged such the no queens are attacking any other queens. The N-Queens Problem is believed to be a NP-Complete Problem which means only non-deterministic polynomial time algorithms solve the problem. I bought copies of Foundations of Constraint Satisfaction by E. P. K. Tsang for Professor Dozier and me in 2000. The back-marking algorithm is found in section 5.4.3 page 147 of the textbook. I implemented several algorithms from the textbook. Below is the source code for the back-marking algorithm and single runs from N = 4 to N = 12. A single run is not a statistically significantly experiment. Generally, 30 or more experimental trials are needed for statistical significance.
/*
Author: James Pate Williams, Jr. (c) 2000 - 2023
Backmarking algorithm applied to the N-Queens CSP.
Algorithm from _Foundations of Constraint Satisfaction_
by E. P. K. Tsang section 5.4.3 page 147.
*/
#include <iomanip>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <vector>
#include <chrono>
using namespace std::chrono;
using namespace std;
// https://www.geeksforgeeks.org/measure-execution-time-function-cpp/
int constraintsViolated(vector<int>& Q) {
int a, b, c = 0, i, j, n;
n = Q.size();
for (i = 0; i < n; i++) {
a = Q[i];
for (j = 0; j < n; j++) {
b = Q[j];
if (i != j && a != -1 && b != -1) {
if (a == b) c++;
if (i - j == a - b || i - j == b - a) c++;
}
}
}
return c;
}
bool satisfies(int x, int v, int y, int vp) {
if (x == y) return false;
if (v == vp) return false;
if (x - y == v - vp || x - y == vp - v) return false;
return true;
}
bool Compatible(int x, int v, int* LowUnit, int* Ordering, int** Mark,
vector<int> compoundLabel) {
bool compat = true;
int vp, y = LowUnit[x];
while (Ordering[y] < Ordering[x] && compat) {
if (compoundLabel[y] != -1) {
vp = compoundLabel[y];
if (satisfies(x, v, y, vp))
y = Ordering[y] + 1;
else
compat = false;
}
}
Mark[x][v] = Ordering[y];
return compat;
}
bool BM1(int Level, int* LowUnit, int* Ordering, int** Mark,
vector<int> unlabelled, vector<int> compoundLabel, vector<int>& solution) {
bool result;
int i, v, x, y;
vector<int> Dx(compoundLabel.size());
if (unlabelled.empty()) {
for (i = 0; i < (int)compoundLabel.size(); i++)
solution[i] = compoundLabel[i];
return true;
}
for (i = 0; i < (int)unlabelled.size(); i++) {
x = unlabelled[i];
if (Ordering[x] == Level) break;
}
result = false;
for (i = 0; i < (int)compoundLabel.size(); i++)
Dx[i] = i;
do {
// pick a random value from domain of x
i = rand() % Dx.size();
v = Dx[i];
vector<int>::iterator vIterator = find(Dx.begin(), Dx.end(), v);
Dx.erase(vIterator);
if (Mark[x][v] >= LowUnit[x]) {
if (Compatible(x, v, LowUnit, Ordering, Mark, compoundLabel)) {
compoundLabel[x] = v;
vIterator = find(unlabelled.begin(), unlabelled.end(), x);
unlabelled.erase(vIterator);
result = BM1(Level + 1, LowUnit, Ordering, Mark,
unlabelled, compoundLabel, solution);
if (!result) {
compoundLabel[x] = -1;
unlabelled.push_back(x);
}
}
}
} while (!Dx.empty() && !result);
if (!result) {
LowUnit[x] = Level - 1;
for (i = 0; i < (int)unlabelled.size(); i++) {
y = unlabelled[i];
LowUnit[y] = LowUnit[y] < Level - 1 ? LowUnit[y] : Level - 1;
}
}
return result;
}
bool Backmark1(vector<int> unlabelled, vector<int> compoundLabel, vector<int>& solution) {
int i, n = compoundLabel.size(), v, x;
int* LowUnit = new int[n];
int* Ordering = new int[n];
int** Mark = new int* [n];
for (i = 0; i < n; i++)
Mark[i] = new int[n];
i = 0;
for (x = 0; x < n; x++) {
LowUnit[x] = 0;
for (v = 0; v < n; v++)
Mark[x][v] = 0;
Ordering[x] = i++;
}
return BM1(0, LowUnit, Ordering, Mark, unlabelled, compoundLabel, solution);
}
void printSolution(vector<int>& solution) {
char hyphen[256] = { '\0' };
int column, i, i4, n = solution.size(), row;
if (n <= 12) {
for (i = 0; i < n; i++) {
i4 = i * 4;
hyphen[i4 + 0] = '-';
hyphen[i4 + 1] = '-';
hyphen[i4 + 2] = '-';
hyphen[i4 + 3] = '-';
}
i4 = i * 4;
hyphen[i4 + 0] = '-';
hyphen[i4 + 1] = '\n';
hyphen[i4 + 2] = '\0';
for (row = 0; row < n; row++) {
column = solution[row];
cout << hyphen;
for (i = 0; i < column; i++)
cout << "| ";
cout << "| Q ";
for (i = column + 1; i < n; i++)
cout << "| ";
cout << '|' << endl;
}
cout << hyphen;
}
else
for (row = 0; row < n; row++)
cout << row << ' ' << solution[row] << endl;
}
int main(int argc, char* argv[]) {
while (true)
{
int i, n;
cout << "Number of queens (4 - 12) (0 to quit): ";
cin >> n;
if (n == 0)
break;
if (n < 4 || n > 12)
{
cout << "Illegal number of queens" << endl;
continue;
}
auto start = high_resolution_clock::now();
vector<int> compoundLabel(n, -1), solution(n, -1), unlabelled(n);
for (i = 0; i < n; i++)
unlabelled[i] = i;
if (Backmark1(unlabelled, compoundLabel, solution))
printSolution(solution);
else
cout << "problem has no solution" << endl;
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Runtime: " << setprecision(3) << setw(5)
<< (double)duration.count() / 1.0e3 << " milliseconds" << endl;
}
return 0;
}








A Northrup P-61 Black Widow drop tank can hold 310 US gallons of high-octane gasoline. The P-61 can carry two to four drop tanks. 310 US gallons weighs 310 gallons * 6.1 pounds = 1,891 pounds. So, the contents of four drop tanks weigh 1,891 pounds * 4 = 7,564 pounds. Neglecting the weight of the drop tank itself, a single P-61 could dump over 3 tons (one US ton = 2,000 pounds) in drop tanks onto friendly or enemy territory. I wonder just how many people were killed by objects ejected prematurely from bombers and fighters in World War II.
I have been interested in solving the Traveling Salesperson problem (TSP) since the early 2000’s. I have used several evolutionary techniques. This blog will cover my implementation of a path genetic algorithm created by me in 2017. Of course, the world’s best TSP solver is the University of Waterloo Conrcorde:
https://www.math.uwaterloo.ca/tsp/concorde.html
which now uses a linear programming solver. I used the programming language C# in my implementations.


The previous graph reminds me of John Travolta dancing to the Bee Gees hit song “Staying Alive”.




The previous data for a 127-city tour is not optimal.

The left length is 123,004 and the right length is 121,697. I don’t know if the right length is optimal. The tour in the literature is bier-127.
03-04-2009 Math Grades at Georgia Tech (1980 – 1983)
The applied numerical analysis that I have been doing lately reminds of my not-so-great experience at Georgia Tech in 1980 to 1983. In that long bygone era, I was an untreated schizophrenic later diagnosed as bipolar undergoing some pretty difficult times. I was having some strangely seriously disabling delusions about the CIA and other branches of the federal government. As I have probably stated in other slide presentations on this site, perhaps even too many times, I knew I was delusional, but I could not stop dwelling on these fictitious thoughts. Anyway, I miraculously was able to take and complete a few senior level engineering or math major math courses and three graduate level math courses. Here are the courses and my grades:
MATH 4582 – Advanced Engineering Mathematics – B, 3 Quarter Hours
MATH 4347 – Partial Differential Equations – B, 3 Hours
MATH 4583 – Vector Analysis – B, 3 Hours
MATH 4320 – Complex Analysis – B, 3 Hours
MATH 4338 – Partial Differential Equations – A, 3 Hours
MATH 6581 – Calculus of Variations – A, 3 Hours
MATH 4640 – Scientific Computing I – B, 3 Hours
MATH 4311 – Introduction to Analysis I – C, 4 Hours
MATH 6341 – Partial Differential Equations I – B, 3 Hours
MATH 4312 – Introduction to Analysis II – B, 4 Hours
MATH 6342 – Partial Differential Equations – D, 3 Hours
I have perhaps legitimate excuses for the C and D. I failed to show up for one of my analysis tests and I received a 0. In the PDE course in which I made a D, I failed to do a term computer project, because I temporarily lost access to LaGrange College’s DG Eclipse minicomputer, and I was scared to death of the CDC Cyber mainframe on the GT campus. I had a CDC FORTRAN manual, but I had no training with the CDC Compass OS. Also, I don’t remember if the DG Eclipse in the chemistry x-ray crystallography lab had either a BASIC interpreter or Fortran or Pascal compilers.
A-grades at GT in those days were very hard to get. I can’t remember whether my introduction to Bessel functions and Legendre polynomials was in MATH 4582 or MATH 4338. I had not taken a formal ordinary differential equations course at LaGrange College, but I was an autodidact (self-taught person) in that area of advanced enginneering mathematics.
I think I could take an applied numerical analysis or partial differential equation course at any institution of higher learning today and do fairly well.
03-04-2009 CHEM 6151 1982 Georgia Tech
I took CHEM 6151 X-Ray Crystallography in the winter of 1982 under the Head of the Chemistry Department. The professor was a top-notched x-ray crystallographer and researcher. Anyway, I wound up with a B in the course since I did not do the optional actual x-ray crystallography analysis of a previously unknown crystal structure. A true chemical, physical, and mathematical genius who had 4.0 averages at Tech both as an undergraduate and graduate student did very well on his crystal and, of course, made an A in the course. This guy was studying nuclear chemistry, and he could easily unravel and decipher any type of spectral data whether it was done by alpha, beta, or gamma spectroscopy, IR, mass, NMR, UV, or visible spectroscopy. I could with great difficulty analyze some spectral data, but I was not even marginally as proficient as the genius.
Again, I think I was afraid of the x-ray crystallography equipment since I thought the government could use spurious x-rays to read my thoughts. I could have used an aluminum hat to deflect the x-rays, but I was even too paranoid for that insane gesture.
03-06-2009 Bailout Insanity
I voted for President Obama, and I really don’t think I had any other viable option with the exception of a vote for the unelectable Ralph Nader. I do wonder about the sanity of the financial sector bailout initiated by former President Bush (good riddance) to the tune of $350 billion out of $700 billion available and also the most recent economic stimulus package signed by President Obama. All these “bailouts or stimuli” are very reminiscent of the desperate measures taken by FDR during the onset of the great depression. Don’t get me wrong, I like FDR a lot, but the massive public works programs he started were nothing more than a somewhat ineffective economic band-aid. It took the Imperialistic Japanese and the mentally ill Nazis with WWII to really recover to a certain extent our economy. Then there was the great economic bust immediately following WWII when the factories geared down production from the peak WWII levels, released all the highly skilled female employees, and the large number of armed services personnel returned to no jobs. Only the GI bill, Marshall Plan, and other ingenious economic downturn countermeasures saved us for the baby booming times of the late 1940s and early 1950s. You can’t just wantonly throw federal money at a set of serious economic problems without some very long term strategic as well as tactical planning. Just creating a lot of construction jobs is a 1930s approach and inherently destabilizing today. As the old actor (“Water World” villain whose name evades me) states in a television commercial about retirement: “You have to have a plan”. Well, I don’t think either the former President, current President, or Congress really has long range plan and what we are looking at now is a lot of panic, put your finger in the dike thinking.
P. S. Fortunately, for me, President Bush enacted the second tier of unemployment benefits that I am collecting for about the next 10 or so weeks.
P. S. S. I thought the pundits said that the bottom of the stock market was at the INDU level of 7,000 now it is about 6,500. AFLAC stock has lost almost 5/6’s of its peak value about last March. Google has lost over half its stock value. We have similar situations with Amazon and Apple stocks. The technology stocks are still better off than the financial related stocks with Bank of America stock worth less than a $1.00 a share. In LaGrange, Georgia, U. S., the January unemployment rate was over 14%, a hefty increase from 6.7% a year ago. My county, Troup County’s unemployment rate was 12.2% up from 10.3% in December 2008 and 6.7% in December 2007. These are the scariest economic times that I can remember. I am ready to be a greeter at WAL-MART, if and only if, I can get the job.
I have developed a long integer package in C++ using H. T. Lau’s “A Numerical Library in C for Scientists and Engineers”. That library is based on the NUMAL Numerical Algorithms in Algol library. I use 32-bit integers (long) as the basis of the LongInteger type. The base (radix) is 10000 which is the largest base using 32-bit integers. As a test of the library, I use Pollard’s original rho factorization method. I utilized the Alfred J. Menezes et al “Handbook of Applied Cryptography” Miller-Rabin algorithm and ANSI X9.17 pseudo random number generator with Triple-DES as the encryption algorithm. I translated Hans Riesel Pascal code for Euclid’s algorithm and the power modulus technique. I don’t use dynamic long integers a la Hans Riesel’s Pascal multiple precision library. The single precision is 32 32-bit longs and multiple precision 64 32-bit longs.
Here is a typical factorization:
Number to be factored, N = 3 1234 5678 9012
Factor = 3
Is Factor prime? 1
Factor = 4
Is Factor prime? 0
Factor = 102 8806 5751
Is Factor prime? 1
Function Evaluations = 6
Number to be factored, N = 0
The first number of N is the number of base 10000 digits. I verified that 10288065751 was prime using Miller-Rabin and the table found online below:
http://compoasso.free.fr/primelistweb/page/prime/liste_online_en.php



