Up to Main Index                            Up to Journal for August, 2024

                     JOURNAL FOR SUNDAY 18TH AUGUST, 2024
______________________________________________________________________________

SUBJECT: Adventures in AI + Tail call recursion optimizations in Mote
   DATE: Sun 18 Aug 20:10:25 BST 2024

Recently, work life has been keeping me busy. I’ve continued to work on Google
training courses. I now have 36 skill badges in GCP, Kubernetes and Artificial
Intelligence.

Over the past week I’ve been focusing mostly on AI. It’s been… interesting…

Currently the computing world is hyped up on AI more than a toddler on a sugar
rush. If there is interest, maybe I’ll write more about my AI adventures in
the journal.

The language models (LLMs) I have been working with are gemma2:2b for general
work and llava for image analysis. My desktop has an Nvidia T1000 8Gb graphics
card. Not a top of the range power house, but it seems to fair quite well and
running models for AI tasks locally is quite usable.

Most of my work has centred around getting an AI to run locally — on modest
hardware, with no services or networking involved — and to experiment with the
AI to explore its capabilities, how best to interact with the AI and how the
AI might be put to use. I’ve even have the AI running on a Raspberry Pi 4 ;)

To that end I’ve been summarising my experiments into a presentation for my
colleagues. I’ll be showing how to get started installing the AI and some
basic prompt engineering: text summation, generating draft emails and other
text, determining sentiment and intent and some image analysis. I also have a
demo I’ve written integrating a Go web service with the AI. Hopefully all this
will encourage and motivate them to experiment on their own.

In other news…

Go 1.23 was released this week on the 13th August. I’ve not found the time yet
to take a look, however I have read the release notes. The main new feature
seems to be the range-over-func functionality, something I’m going to have to
look at sooner rather than later.

That’s enough about work life, let’s talk about Mote…

I’ve been working on Mote, the next version of my Mere programming language,
as time permits. Regular expression handling operators have been added with
copious tests. These are the same as implemented in the first version of Mere.

The “big ticket” item I’ve been working on for Mote is tail call recursion
optimizations. Tail call recursion is when the final operation in a function
is a ’return’ expression that calls the same function again. For example:


    func fn
      # do something interesting
      return call fn
    end


In the above code there is no need for the runtime to create a new call state.
The final return call requires no further information about the current call
and so the current state can be reused. By not saving a new call state for
every call there is less unwinding of the call stack later on. This improves
performance and reduces the runtime memory overhead. The first version of Mere
did not have this optimization.

For example, consider a simple recursive function:


    println call repeat "*" 5

    func repeat s n
      is len s == n; return s
      return call repeat s+s[0], n
    end


When run, the above code produces:


    >mote example.src
    *****
    >


Looking at the end of the trace for the above code, when optimizations are
turned off, we see:


    Trace started (address, line, op/fn, args):
    0x0000001F           6   return | s["…"] V[0x03:repeat∙s:s]
    0x0000002B           7   return | s["…"] s["*****"]
    0x0000002B           7   return | s["…"] s["*****"]
    0x0000002B           7   return | s["…"] s["*****"]
    0x0000002B           7   return | s["…"] s["*****"]
    0x0000000C           3  println | s["…"] s["*****"]


The 5 ‘return’ operations are the stack unwinding from the recursive calls.
However, looking at the trace when optimizations are turned on we see:


    Trace started (address, line, op/fn, args):
    0x0000001F           6   return | s["…"] V[0x03:repeat∙s:s]
    0x0000000C           3  println | s["…"] s["*****"]


Here we see that with optimizations turned on there is no stack unwinding.

Testing with a simple recursive factorial example, shown below, yields a 36%
improvement in performance:


    for x = 1; x <= 20; x++
      printf "%2d! = %d\n", x, call factorial x
    next

    println elapsed()["autoMicro"]

    func factorial N
      return call fn N 1

      func fn N acc
        is N == 0; return acc
        return call fn N-1, N*acc
      end
    end

The optimization will work for multiple exit paths as well. For example
consider:


    println call recur

    func recur
      is kind N == "undefined"; N = 0
      N++
      is N == 3; return N
      is N == 2; return call recur N
      return call recur N
    end


Here we have two recursive calls to recur. One is taken if “N == 2” and the
other is the final default case. With optimizations turned off we see the
stack unwinding again:


    Trace started (address, line, op/fn, args):
    0x00000028           8   return | s["…"] V[0x03:recur∙N:i]
    0x00000035           9   return | s["…"] i[3]
    0x0000003C          10   return | s["…"] i[3]
    0x0000000A           3  println | s["…"] i[3]


With the optimizations turned on there is no stack unwinding:


    0x00000028           8   return | s["…"] V[0x03:recur∙N:i]
    0x0000000A           3  println | s["…"] i[3]


I tend to use recursion a lot, so I’m quite happy with this change :)

The next step for Mote is to clean up some example programs I’ve been working
on. Then I need to get the new ICE (Integrated Code Environment) finished,
rewriting all of the information and example code is not going to be fun. Once
that is done I should be able to replace the current Mere version in the annex
with the Mote version.

Mere ICE in the annex will still be labelled as early access, but it will show
progress and allow people to have a play and experiment.

To end, a haiku generated by the AI, about AI:

                           Questions unanswered,
                           Algorithms ponder deep,
                           Truth waits in the code.

--
Diddymus


  Up to Main Index                            Up to Journal for August, 2024