Apr 282023
 

I cannot teach GPT-4 how to play chess. Conceptualizing a chessboard and making a move are beyond its capabilities.

However, it was able to write (with minimal guidance from me) nice code to display and update a chessboard. That is quite impressive on its own right. It took several tries to get the board right but it did succeed in the end.

 Posted by at 2:33 am
Apr 182023
 

So here is my latest conversation with GPT-4 using my custom user interface. The important features of this implementation are the following:

  1. GPT is instructed to use LaTeX for mathematical output, which the UI correctly renders;
  2. The UI captures and renders SVG graphics that GPT may generate;
  3. GPT can use an external computer algebra tool for accurate computation;
  4. GPT can invoke an external tool to perform Google searches for current information;
  5. Conversations are condensed to ensure that they can run effectively indefinitely without hitting the token limit;
  6. GPT is used efficiently (GPT3.5 used for summaries, GPT-4 for new queries);
  7. The UI is optimized for easy printing (to PDF or hardcopy).

I was able to achieve this level of integration even without plugin-level access, simply by clever “prompt engineering” to ensure that the majority of the time, GPT uses the provided tools effectively. For this, GPT-4 seems essential; GPT3.5 is not really able to grasp the notion of using external tools before constructing its answers.

By way of example, when GPT was asked about the current Bank of Canada interest rate, what happened in the background was the following exchange:

User: What is the current Bank of Canada interest rate?

GPT: SEARCH(“current Bank of Canada interest rate”)

User: Snippet 1: Mar 8, 2023 … The current Bank of Canada interest rate sits at 4.50%, with a 0.25% rate hike announced on January 25, 2023.
Snippet 2: See the Current Bank of Canada Interest Rate graphs at this page. You will read in the news about this rate when the Bank of Canada makes a rate …
Snippet 3: Find answers about questions you may have about the Bank of Canada. What is the current bank of Canada interest rate?

GPT: As of March 8, 2023, the current Bank of Canada interest rate is 4.50%. A 0.25% rate hike was announced on January 25, 2023.

The prompting that I use can of course be improved. The behavior of GPT-4 is not always consistent, sometimes it fails to make use of the computer algebra result or attempts to invoke computer algebra in the wrong place. I suspect that the “right” solution will have to wait until I have plugin-level developer access. But I am very happy that I was able to accomplish this already, in particular that access to Google and the computer algebra tool are completely automated in the background, requiring no user action.

 Posted by at 3:08 am
Feb 272023
 

More than 20 years ago, I wrote a program that showed what Mars would look like if it had oceans.

I wrote it originally in C++, but then ported it to Java and turned it into a Web application.

That was a long time ago. Unfortunately, browsers no longer support Java applets for security reasons. So my beautiful applet was not working anymore.

Today, I finally spent some time reimplementing the applet in plain JavaScript. It’s working again! (Apart from some minor cosmetics.) And it has data sets for Mars, Earth, Venus and the Moon as well.

 Posted by at 2:47 am
Dec 092022
 

I really should stop messing with ChatGPT but…

I asked it some more physics questions and got moderately mediocre answers. For instance, when I asked it about the conformal group in four spacetime dimensions, it described it as consisting of the Lorentz-Poincare group plus dilations. Many physicists would say the same thing but this is an incomplete description, leaving out the most interesting bit, the so-called special conformal group. But when I asked it to describe the special conformal group it offered a decent answer; it did mention inversion, what it failed to mention was that it really is an inversion with respect to the unit circle, a translation, and a second inversion and as such, it introduces four additional degrees of freedom.

But then, I went back to asking programming questions. I thought by now that I had a good sense of the algorithm’s limitations. So I dug up an old utility I once wrote and asked ChatGPT about the code.

Can you tell me what the following C-language program does under Linux?

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

void main(void)
{
  int i, j, k, l;

  for (i = 0; i <= 32767; i++)
  {
    if (kill(i, 0) == 0 || errno == EPERM)
    {
      char s[120], f[20], c[100];
      FILE *p;

      sprintf(s, "%6d ", i);
      sprintf(f, "/proc/%d/status", i);
      if (p = fopen(f, "r"))
      {
        l = fread(c, 1, sizeof(c), p);
        fclose(p);
        for (j = 0; j < l && c[j] != '\t'; j++);
        for (k = 7, j++; j < l && c[j] != '\n'; j++) s[k++] = c[j];
        s[k] = '\0';
      }
      printf("%s\n", s);
    }
  }
}

This C-language program is a simple utility that lists the active processes on a Linux system. When run, the program will iterate through all possible process IDs from 0 to 32767, and check if a process with that ID exists on the system. If a process with the given ID exists, the program will print information about that process, including its process ID, process name, and other details.

To do this, the program uses the kill function from the signal.h library to check if a process with a given ID exists. The kill function is typically used to send signals to processes, but it can also be used to check if a process with a given ID exists by calling it with a signal value of 0.

If the kill function returns 0 or sets the errno value to EPERM, this indicates that a process with the given ID exists on the system. In this case, the program will use the sprintf function to create a string containing the process ID, and then open the /proc/[pid]/status file, where [pid] is the process ID, using the fopen function.

The status file contains information about the process, including its name and other details. The program will read the contents of this file using the fread function and extract the process name from the file using string manipulation. The extracted process name will be appended to the string containing the process ID, and the resulting string will be printed to the console using the printf function.

Overall, this program is a simple example of how to list the active processes on a Linux system using the kill and /proc functions. It is worth noting that this program is not intended for use in a production environment, as it is not robust or efficient. It is intended only as a simple demonstration of the concept.

OK, this isn’t even funny anymore. But surely, a program that actually prints two-dimensional ASCII graphics using an obscure algorithm will leave the AI baffled?

What does the following program do?

#include <stdio.h>
#include <string.h>

#define R 20

void main(void)
{
  int x, y, d, dA, dB;
  int i;

  char B[2*R+1][2*R+2];

  memset(B, ' ', sizeof(B));
  for (i = 0; i < 2*R+1; i++) B[i][2*R+1] = 0;

  x = 0;
  y = R;
  d = 5 - (R<<2);
  dA = 12;
  dB = 20 - (R<<3);
  while (x<=y)
  {
    B[R+x][R+y] = B[R+x][R-y] = B[R-x][R+y] = B[R-x][R-y] =
    B[R+y][R+x] = B[R+y][R-x] = B[R-y][R+x] = B[R-y][R-x] = 'X';
    if (d<0)
    {
      d += dA;
      dB += 8;
    }
    else
    {
      y--;
      d += dB;
      dB += 16;
    }
    x++;
    dA += 8;
  }
  for (i = 0; i < 2*R+1; i++) printf("%s\n", B[i]);
}

This program is a simple implementation of the midpoint circle algorithm, which is used to draw a circle on a two-dimensional grid. When run, the program will print a circle with a radius of 20 units, using the character ‘X’ to mark the points on the circle.

To do this, the program first defines a 2-dimensional array named B with dimensions 2*R+1 by 2*R+2, where R is the radius of the circle. The array is initialized with spaces using the memset function, and the last column of the array is set to 0 using a for loop.

Next, the program sets the initial values for the variables used in the midpoint circle algorithm. These include the current x and y coordinates of the point being considered, as well as various intermediate values used to compute the next point on the circle.

The program then enters a while loop that continues until the value of x is greater than or equal to the value of y. Inside the while loop, the program uses the midpoint circle algorithm to compute the next point on the circle, given the current point. This involves checking if the value of d is less than 0, and computing new values for d, x, and y based on the result.

Once the new values have been computed, the program sets the corresponding element in the B array to 'X', to mark the point on the circle. The program then increments the value of x and updates the values of the other intermediate variables used in the algorithm.

After the while loop ends, the program uses a for loop to print each row of the B array to the console, resulting in a grid containing a circle with a radius of 20 units, drawn using the character 'X'.

No, it’s not OpenGPT that is baffled. I am baffled. Beyond speechless.

 Posted by at 6:19 pm
Dec 092022
 

Despite my misgivings concerning the many “teacher’s pet” style answers offered by ChatGPT, I could not resist messing with it some more.

First, since everybody does it, I also asked it to describe something nontrivial in the style of the King James Bible:

Can you describe the trolley problem written in the style of the King James Bible?

Sure, I can try to describe the trolley problem in the style of the King James Bible. Here is my attempt:

Verily, there was a great dilemma that faced a righteous man. A trolley was careening down a track, and on its path were five workers, toiling on the line. The man had the power to divert the trolley onto a different track, but lo, on this track was but a single worker, also toiling on the line.

The man was torn between two choices: to do nothing and allow the trolley to continue its course, resulting in the death of five workers, or to take action and divert the trolley onto the other track, resulting in the death of a single worker.

What, then, should the man do? Should he sacrifice the life of the one to save the lives of the many, or should he let the trolley continue on its path and allow the deaths of the five?

This was a most difficult decision, and the man knew not what to do. But in the end, he made a choice, and the consequences of his actions weighed heavily upon him.

But then, I thought I’d offer it a real challenge. Can it recognize a perfectly functional, decently written but somewhat obtuse piece of C code for what it does? Note the paragraph in the answer that I highlighted in red.

Can you tell me what the following C-language code fragment does?

#include <string.h>

double Z(double z)
{
  if (z < 0 || z > 170 || z != floor(z)) return strtod("NaN", NULL);
  if (z == 0) return 1;
  else return z * Z(z - 1);
}

This code defines a recursive function named Z that takes a single double argument named z. The function first checks if the value of z is less than 0, greater than 170, or not an integer. If any of these conditions are true, the function returns the result of calling the strtod function with the string "NaN" and a NULL value as arguments. This would convert the string "NaN" to a double value representing “Not a Number”.

If the value of z is not less than 0, greater than 170, or not an integer, the function then checks if z is equal to 0. If this is the case, the function returns the value 1.

If z is not 0, the function returns the result of z multiplied by the result of calling the Z function with z - 1 as the argument. This means that the Z function calls itself with a z value that is 1 less than the current z value. This is an example of recursion, where a function calls itself with a modified input until a base case is reached. In this case, the base case is when z is equal to 0. When this happens, the function returns 1 and the recursive calls “unwind”, returning the final result of the Z function.

It is worth noting that this Z function is an implementation of the factorial function, which calculates the product of all positive integers less than or equal to a given integer n. For example, the factorial of 5, written as 5!, is equal to 5 * 4 * 3 * 2 * 1 = 120. This Z function would return the same result if it were called with an argument of 5.

Holy mackerel. Seriously.

 Posted by at 2:30 pm
Dec 092022
 

Inspired by examples I saw elsewhere, I figured I’d test ChatGPT some more. This time around, I asked it to spot a programming error, and while its answer was flawed, it was not altogether wrong.

Here is our brief conversation (ChatGPT also adds some nice colorized code formatting that I shall not attempt to reproduce here):

Can you spot the bug in the following C-language code fragment?

char *str = "SOME TEXT";
char *buf = malloc(strlen(str));
strcpy(buf, str);

The code is missing a null terminator character '\0' at the end of the string assigned to buf. The strcpy function does not automatically add a null terminator character when copying the string from str to buf, so buf will not be a properly-formatted string.

To fix the code, you can add a null terminator character to the end of buf after it has been copied from str, like this:

char *str = "SOME TEXT";
char *buf = malloc(strlen(str) + 1); // Add one to include space for the null terminator character
strcpy(buf, str);
buf[strlen(str)] = '\0'; // Add the null terminator character at the end of the string

Alternatively, you can use the strdup function to copy str into buf, which automatically adds a null terminator character to the end of the copied string, like this:

char *str = "SOME TEXT";
char *buf = strdup(str);

Note that the strdup function is not a standard C library function and may not be available on all platforms.

Pretty darn close! The AI correctly noticed that there is a problem with the terminating null character. But it’s not what it says: it’s not that strcpy won’t copy the string terminator. Quite the contrary, the problem is that strcpy does copy that terminating null, but we have not allocated memory for it: strlen returns the length of the string without that terminator.

Interestingly, the AI seems to be aware of this as in the corrected version, it adds room for that extra byte. The corrected code is error-free but redundant: the last line is not required, because strcpy would have already copied the terminating null. This line would be required, on the other hand, if we had used strncpy.

The suggestion to use strdup is a good one, except that contrary to the caveat, strdup is now part of the upcoming ISO C standard.

Still, it is doing better already than many a C programmer I knew. So how about offering it a really tricky related problem?

The following C-language code fragment works:

char *str = "SOME TEXT";
char *buf = malloc(strlen(str));
strcpy(buf, str);

but if I replace the first line with

char *str = "A DIFFERENT TEXT";

the program crashes. Can you explain why?

When you replace the first line of the code with char *str = "A DIFFERENT TEXT";, the length of the string assigned to str increases, but the size of the memory allocated for buf remains the same. This causes a buffer overflow, which can lead to a crash or other undefined behavior.

To fix this issue, you can use the strlen function to calculate the length of the string assigned to str and allocate enough memory for buf to hold the entire string, like this:

char *str = "A DIFFERENT TEXT";
char *buf = malloc(strlen(str) + 1); // Add one to include space for the null terminator character
strcpy(buf, str);

Alternatively, you can use the strdup function to copy str into buf, which automatically allocates enough memory for the entire string, including the null terminator character, like this:

char *str = "A DIFFERENT TEXT";
char *buf = strdup(str);

Note that the strdup function is not a standard C library function and may not be available on all platforms.

Really close! But no, it’s not that the size of the memory allocated for the buffer remains the same. It’s that in both cases, the size of the memory allocated for the buffer failed to include room for the terminating null character. However, in the first case the string was 9 bytes long, or 10 with the terminating null. On most modern platforms, memory is allocated in units of 32-bit words or larger, so at the very least, there’d he 12 bytes allocated, leaving enough room for the terminator. But in the second case, the text is exactly 16 bytes long. Chances are that the call to malloc will allocate exactly 16 bytes, and therefore, copying the terminating null will cause a buffer overflow, overwriting something else that it shouldn’t.

Still, even though its reasoning is flawed, the AI’s proposed fix is spot on: include room for the null terminator!

I am not unimpressed. Yet all these examples tend to remind me of the behavior of the “teacher’s pet” A-student who memorizes a lot, can even apply simple reasoning, but lacks in-depth understanding.

 Posted by at 12:29 pm
Apr 272022
 

Someone reminded me that 40 years ago, when we developed games for the Commodore-64, there were no GPUs. That 8-bit CPUs did not even have a machine instruction for multiplication. And they were dreadfully slow.

Therefore, it was essential to use fast and efficient algorithms for graphics primitives.

One such primitive is Bresenham’s algorithm although back then, I didn’t know it had a name beyond being called a forward differences algorithm. It’s a wonderful, powerful example of an algorithm that produces a circle relying only on integer addition and bitwise shifts; never mind floating point, it doesn’t even need multiplication!

Here’s a C-language implementation for an R=20 circle (implemented in this case as a character map just for demonstration purposes):

#include <stdio.h>
#include <string.h>

#define R 20

void main(void)
{
    int x, y, d, dA, dB;
    int i;
    char B[2*R+1][2*R+2];

    memset(B, ' ', sizeof(B));
    for (i = 0; i < 2*R+1; i++) B[i][2*R+1] = 0;

    x = 0;
    y = R;
    d = 5 - (R<<2);
    dA = 12;
    dB = 20 - (R<<3);
    while (x<=y)
    {
        B[R+x][R+y] = B[R+x][R-y] = B[R-x][R+y] = B[R-x][R-y] =
        B[R+y][R+x] = B[R+y][R-x] = B[R-y][R+x] = B[R-y][R-x] = 'X';
        if (d<0)
        {
            d += dA;
            dB += 8;
        }
        else
        {
            y--;
            d += dB;
            dB += 16;
        }
        x++;
        dA += 8;
    }

    for (i = 0; i < 2*R+1; i++) printf("%s\n", B[i]);
}

And the output it produces:

                XXXXXXXXX                
             XXX         XXX             
           XX               XX           
         XX                   XX         
        X                       X        
       X                         X       
      X                           X      
     X                             X     
    X                               X    
   X                                 X   
   X                                 X   
  X                                   X  
  X                                   X  
 X                                     X 
 X                                     X 
 X                                     X 
X                                       X
X                                       X
X                                       X
X                                       X
X                                       X
X                                       X
X                                       X
X                                       X
X                                       X
 X                                     X 
 X                                     X 
 X                                     X 
  X                                   X  
  X                                   X  
   X                                 X   
   X                                 X   
    X                               X    
     X                             X     
      X                           X      
       X                         X       
        X                       X        
         XX                   XX         
           XX               XX           
             XXX         XXX             
                XXXXXXXXX                

Don’t tell me it’s not beautiful. And even in machine language, it’s just a few dozen instructions.

 Posted by at 1:21 am
Mar 162021
 

Somebody just reminded me: Back in 1982-83 a friend of mine and I had an idea and I even spent some time building a simple simulator of it in PASCAL. (This was back in the days when a 699-line piece of PASCAL code was a huuuuge program!)

So it went like this: Operative memory (RAM) and processor are separate entities in a conventional computer. This means that before a computer can do anything, it needs to fetch data from RAM, then after it’s done with that data, it needs to put it back into RAM. The processor can only hold a small amount of data in its internal registers.

This remains true even today; sure, modern processors have a lot of on-chip cache but conceptually, it is still separate RAM, it’s just very fast memory that is also physically closer to the processor core, requiring less time to fetch or store data.

But what if we abandon this concept and do away with the processor altogether? What if instead we make the bytes themselves “smart”?

That is to say what if, instead of dumb storage elements that can only be used to store data, we have active storage elements that are minimalist processors themselves, capable of performing simple operations but, much more importantly, capable of sending data to any other storage element in the system?

The massive number of required interconnection between storage elements may appear like a show-stopper but here, we can borrow a century-old concept from telephony: the switch. Instead of sending data directly, how about having a crossbar-like interconnect? Its capacity will be finite, of course, but that would work fine so long as most storage elements are not trying to send data at the same time. And possibly (though it can induce a performance penalty) we could have a hierarchical system: again, that’s the way large telephone networks function, with local switches serving smaller geographic areas but interconnected into a regional, national, or nowadays global telephone network.

Well, that was almost 40 years ago. It was a fun idea to explore in software even though we never knew how it might be implemented in hardware. One lesson I learned is that programming such a manifestly parallel computer is very difficult. Instead of thinking about a sequence of operations, you have to think about a sequence of states for the system as a whole. Perhaps this, more than any technical issue, is the real show-stopper; sure, programming can be automated using appropriate tools, compilers and whatnot, but that just might negate any efficiency such a parallel architecture may offer.

Then again, similar ideas have resurfaced in the decades since, sometimes on the network level as massively parallel networks of computers are used in place of conventional supercomputers.


Gotta love the Y2K bug in the header, by the way. Except that it isn’t. Rather, it’s an implementation difference: I believe the PDP-11 PASCAL that we were using represented a date in the format dd-mm-yyyy, as opposed to dd-MMM-yyyy that is used by this modern Pascal-to-C translator. As I only allocated 10 characters to hold the date in my original code, the final digit is omitted. As for the letters "H J" that appear on top, that was just the VT-100 escape sequence to clear the screen, but with the high bit set on ESC for some reason. I am sure it made sense on the terminals that we were using back in 1982, but xterm just prints the characters.

 Posted by at 12:54 pm
Feb 102021
 

Sometimes, simple programming mistakes make for interesting glitches.

Take this image:

No, this is not something that a gravitational lens would produce. Or any lens.

Even-numbered multipoles in a gravitational lens produce images that have fourfold symmetry. This allows me to reduce the amount of computation needed to generate an image, as I only need to generate one quarter; the rest are just copied over.

But this is not true for odd-numbered multipoles. This image was supposed to represent the J3 multipole, which would yield a triangular shape.

Unfortunately, I generated it accidentally by assuming the symmetries of an even-numbered multipole.

I kind of like the result, even though it is of course scientifically worthless. It still looks neat though.

 Posted by at 12:36 pm
Nov 192020
 

In recent years, I saw myself mostly as a “centrist liberal”: one who may lean conservative on matters of the economy and state power, but who firmly (very firmly) believes in basic human rights and basic human decency. One who wishes to live in a post-racial society in which your ethnicity or the color of your skin matter no more than the color of your eyes or your hairstyle. A society in which you are judged by the strength of your character. A society in which consenting, loving adults can form families regardless of their gender or sexual orientation. A society that treats heterosexuals and non-heterosexuals alike, without prejudice, without shaming, without rejection. A society in which covert racism no longer affords me “white privilege” while creating invisible barriers to those who come from a different ethnic background.

But then, I read that one of the pressing issues of the day is… the elimination of terms such as “master/slave” or “blacklist/whitelist” from the technical literature and from millions upon millions of lines of software code.

Say what again?

I mean… not too long ago, this was satire. Not too long ago, we laughed when overzealous censors (or was it misguided software?) changed “black-and-white” into “African-American-and-white”. Never did I think that one day, reality catches up with this Monty Pythonesque insanity.

It is one thing to fight for a post-racial society with gender equality. For a society in which homosexuals, transsexuals and others feel fully appreciated as human beings, just like their conventionally heterosexual neighbors. For a society free of overt or covert discrimination.

It is another thing to seek offense where none was intended. To misappropriate terms that, in the technical literature, NEVER MEANT what you suggest they mean. And then, to top it all off, to intimidate people who do not sing exactly the same song as the politically correct choir.

No, I do not claim the right, the privilege, to tell you what terms you should or should not find offensive. I am simply calling you out on this BS. You know that there is/was nothing racist about blacklisting a spammer’s e-mail address or arranging a pair of flip-flops (the electronic components, not the footwear) in a master/slave circuit. But you are purposefully searching for the use of words like “black” or “slave”, in any context, just to fuel this phony outrage. Enough already!

Do you truly want to fight real racism? Racism that harms people every day, that prevents talented young people from reaching their full potential, racism that still shortens lives and makes lives unduly miserable? Racial discrimination remains real in many parts of the world, including North America. Look no further than indigenous communities here in Canada, or urban ghettos or Native American villages in the United States. And elsewhere in the world? The treatment of the Uyghurs in China, the treatment of many ethnic minorities in Russia, human rights abuses throughout Africa and Asia, rising nationalism and xenophobia in Europe.

But instead of fighting to make the world a better place for those who really are in need, you occupy yourselves with this made-up nonsense. And as a result, you achieve the exact opposite of what you purportedly intend. Do you know why? Well, part of the reason is that decent, well-meaning people in democratic countries now vote against “progressives” because they are fed up with your thought police.

No, I do not wish to offer excuses for the real racists, the bona fide xenophobes, the closet nazis and others who enthusiastically support Trump or other wannabe autocrats elsewhere in the world. But surely, you don’t believe that over 70 million Americans who voted for Donald J. Trump 17 days ago are racist, xenophobic closet nazis?

Because if that’s what you believe, you are no better than the real racists, real xenophobes and real closet nazis. Your view of your fellow citizens is a distorted caricature, a hateful stereotype.

No, many of those who voted for Trump; many of those who voted for Biden but denied Democrats their Senate majority; many of those who voted for Biden but voted Democratic congresspeople out of the US Congress: They did so, in part, because you went too far. You are no longer solving problems. You are creating problems where none exist. Worse yet, through “cancel culture” you are trying to silence your critics.

But perhaps this is exactly what you want. Perpetuate the problem instead of solving it. For what would happen to you in a post-racial society with gender equality and full (and fully respected) LGBTQ rights? You would fade back into obscurity. You’d have to find a real job somewhere. You would no longer be able to present yourself as a respected, progressive “community leader”.

Oh, no, we can’t have that! You are a champion of human rights! You are fighting a neverending fight against white supremacism, white privilege, racism and all that! How dare I question the purity of your heart, your intent?

So you do your darnedest best to create conflict where none exists. There is no better example of this than the emergence of the word “cis” as a pejorative term describing… me, among other people, a heterosexual, white, middle-class male, especially one who happens to have an opinion and is unwilling to hide it. Exactly how you are making the world a better place by “repurposing” a word in this manner even as you fight against long-established terminology in the technical literature that you perceive as racist is beyond me. But I have had enough of this nonsense.

 Posted by at 10:46 pm
Nov 112020
 

Did Microsoft just offer me a 14-year old driver as a new update for Windows 10? Oh yes, they did!

But that’s okay… why fix something if it is not broken? Though I do wonder, if it is indeed a 14-year old driver, why was it not part of Windows 10 already? But never mind.

On the plus side, last night Windows 10 performed a feature upgrade along with security updates, and the whole upgrade process finished in well under half an hour; the reboot and installation phase only took a few minutes and so far, as far as I can tell, nothing is broken. Nice.

 Posted by at 12:36 pm
Jun 082020
 

Long overdue, but I just finished preparing the latest Maxima release, version 5.44.

I am always nervous when I do this. It is one thing to mess with my own projects, it is another thing to mess with a project that is the work of many people and contains code all the way back from the 1960s.

 Posted by at 2:11 am
May 222020
 

I am one of the maintainers of the Maxima computer algebra system. Maxima’s origins date back to the 1960s, when I was still in kindergarten. I feel very privileged that I can participate in the continuing development of one of the oldest continuously maintained software system in wide use.

It has been a while since I last dug deep into the core of the Maxima system. My LISP skills are admittedly a bit rusty. But a recent change to a core Maxima capability, its ability to create Taylor-series expansions of expressions, broke an important feature of Maxima’s tensor algebra packages, so it needed fixing.

The fix doesn’t amount to much, just a few lines of code:

It did take more than a few minutes though to find the right (I hope) way to implement this fix.

Even so, I had fun. This is the kind of programming that I really, really enjoy doing. Sadly, it’s not the kind of programming for which people usually pay you Big Bucks… Oh well. The fun alone was worth it.

 Posted by at 12:16 am
Sep 132019
 

My favorite cartoons are Kliban’s cats, but the Dilbert comic strips represent a close second.

Today’s Dilbert offers a perfect demonstration why.

I could actually be the consultant that Dilbert’s pointy-haired boss is looking for. Over the years, I learned one very important thing about this business: As a consultant, my job is to offer my best advice to my customer, but then whatever decision they make, it’s theirs to make, not mine. My job is to continue supporting them to the best of my abilities.

In my career, I have seen customers make bad decisions that destroyed their projects. I offered my advice. When it was ignored, I did not take it personally. Neither that nor judging the customer are part of my job description. That is not to say that I do not feel regret, or that I did not often second-guess myself: Could I have offered better advice? Could I have been more convincing? Why was my advice not accepted?

But judging? Nope. That would be rather unprofessional.

 Posted by at 12:02 am
Jun 052019
 

And before I forget: Last week, wearing my release manager hat I successfully created a new version of Maxima, the open-source computer algebra system. As a result, Maxima is again named one of SourceForge’s projects of the week, for the week of June 10.

The release turned out to be more of an uphill battle than I anticipated, but in the end, I think everything went glitch-free.

Others have since created installers for different platforms, including Windows.

And I keep promising myself that when I grow up, I will one day understand exactly what git does and how it works, instead of just blindly following arcane scripts…

 Posted by at 1:50 pm
Mar 302019
 

Content management software that I use, Joomla! and WordPress in particular, have been complaining for a while now that the PHP version that runs on my servers is outdated and potentially unsecure. Not exactly true, as PHP 5.4 remains part of the official Red Hat/CentOS release, but it would certainly be prudent for me to attempt an upgrade.

I tried to do just that last night, on a test server. And it was a miserable failure, a waste of many hours that I will never get back, to make no mention of the heightened risk of cardiovascular disease due to my elevated blood pressure caused by all that frustration.

The relatively easy part? PHP 7 complaining that its just-in-time compilation feature ran out of memory. Easy-peasy, I can disable JIT. Check.

But then: several of my Joomla! sites refused to run, with a cryptic and ultimately meaningless error message and nothing in the logs. And at least one Joomla! site just got itself into an infinite redirect loop. But why?

I tried many things. I kept looking for answers on Google. Nothing worked. Eventually I took two of my Joomla! sites that are very similar in nature, and began comparing their settings, side-by-side. One worked, the other didn’t. Why?

I then stumbled upon a custom Joomla! module, one that I wrote to support some ads that appear on my sites. This module was installed on the site that failed, but not used on the other. I disabled the module and, presto, the site was working with PHP 7. I re-enabled the module and the site was dead again. So… why?

Well, the module contains some PHP code. Which, after some preamble that allows it to connect to the internal data structures of Joomla!, begins the real work by accessing the MySQL database that contains the actual ads:

$conn = mysql_connect("localhost");
mysql_select_db("www");
$res = mysql_query("SELECT PAGEID,ADTEXT FROM ...

Oops.

You see, mysql_ calls have been deprecated and REMOVED from PHP starting with version 7.

And I have hundreds, if not thousands of lines of legacy code* (including, e.g., my calculator museum at rskey.org) that rely on this old library.

So I guess that PHP 7 upgrade will have to wait a while longer. Looks like I have no choice but to rewrite the affected pieces of code everywhere, as there is no other long-term solution. (Even if I find a third-party PHP plugin that re-enables mysql_ codes, how long will that continue to work? How reliable will it be?)

What a muckup. Grumble. And I do have other work to do.

 Posted by at 10:40 am
Mar 252019
 

The other day, I started listening to Google Music’s personalized music stream.

I am suitably impressed. The AI is… uncanny.

Sure, it picked songs that I expressed a preference for, such as songs from the golden age of radio that I happen to enjoy. But as I continue listening, it is presenting an increasingly eclectic, enjoyable selection. Some of it is quite new, from artists I never heard about, yet… it’s music I like. For some reason (maybe because I am in Canada? Or because it knows that I am trying to improve my French? Or was it a preference I once expressed for Édith Piaf?) it started presenting a whole bunch of French music, and again… some of it is quite likable. And now that I purposefully sought out a few classical composers, the AI realized that it can throw classical pieces at me as well, which is how I am suddenly listening to Schubert’s Ave Maria.

As a matter of fact, the eclectic choices made by Google’s AI remind me of two radio programs from the CBC’s past, long gone, long forgotten by most: Juergen Goth’s Disc Drive and Laurie Brown’s The Signal. Both these shows introduced me to music from excellent artists that I would otherwise never have heard about.

And now Google’s AI is doing the same thing.

I am also getting the sense that the more I listen, the bolder the AI becomes as it makes its choices. Instead of confining me to a bubble of musical genres of my own making, it is venturing farther and farther away from my presumed comfort zone.

Which is quite impressive. But also leaves me wondering how long before our machine overlords finally decide to take over.

 Posted by at 7:27 pm