GSoC Log Entry No. 7

Summary of Progress

This is the final report for my Google Summer of Code 2025 project: Porting Chebfun to GNU Octave.

Introduction

Google Summer of Code is a program, run by Google, that organizes and funds projects related to open-source software. This year, I participated in the program as a mentee under the GNU Octave organization. Under the supervision of my mentors Colin B. Macdonald (Associate Professor, Department of Mathematics, University of British Columbia) and Andreas Bertsatos (Researcher, Science and Technology in Archaeological and Cultural Research Center, The Cyprus Institute), I worked on porting Chebfun, a numerical/symbolic hybrid computing library, from MATLAB to Octave.

What I’ve set out to do

My first blog post also talks about the goals of this project

I realize, though, that my proposal has some jargon that might be hard to decode if you’re not familiar with either of MATLAB, Chebfun or GNU Octave before, so here’s a quick glossary of terms before I try to describe it again:

MATLAB – A numerics-focused computing environment and language, mostly used in academia and in traditional engineering domains (read: not pure software engineering). Not libre software, licenses cost a lot of money and are quite restrictive in terms of deploying code.

GNU Octave – A libre alternative to MATLAB licensed under GPLv3, mostly compatible with MATLAB code. What this means is that most MATLAB code should be able to be run in Octave. Unfortunately, this is not the case for all MATLAB code.

Chebfun – A (very large) MATLAB library that implements a completely novel way of doing numerical computations with functions. It does this by representing functions as piecewise Chebyshev polynomial interpolants, and it overloads many MATLAB operators to work on these function-like objects. Initially created by researchers at the University of Oxford, it has been under active development for over 20 years.

Classdef – MATLAB’s object-oriented programming system, introduced in 2008. GNU Octave supports a fairly basic subset of it, but feature parity nor stability was ever achieved.

The scope of the original project was to port Chebfun from MATLAB to GNU Octave. This project required two different strategies to be employed:

Why is it important to port Chebfun?

It’s a justified question. To start, Chebfun is a permissively licensed (BSD license) library that was developed by academics to experiment with new numerical algorithms and a novel interface for doing mathematical analysis with computers. Chebfun is a wellspring of scientific research with a dedicated book to go along with it. My personal motivation is that it is a shame to see such cool software like that require a proprietary platform to run.

On a more practical note, it is hard to invigorate interest in a software project that exists on a platform that less and less new mathematicians/computer scientists/engineers are learning. Even though Octave has extremely similar syntax to MATLAB, the odds of something picking it up on a whim to try Chebfun are much higher than if they had to invest in a restrictive MATLAB license.

Could you have not ported it to another language, like Python or even a compiled language like C/C++, and had those same benefits?

Short answer is it’s possible, but:

What I’ve got done

Loading and saving of classdef objects

I didn’t really expect to work on this issue at all when I first started the project. It started when I wrote my midterm checklist, which had the line

  • Fix at least one classdef issue in Octave proper.

Ideally, the classdef bug to be patched will be one that plagues the Chebfun codebase somehow. I have not decided on which bug I will dedicate my time to, or how many bugs I could realistically fix; that is something I will learn with experience. The dream would be if Chebfun would immediately start working after a few core Octave patches applied, but since this is very unclear if it is even feasible, I cannot rely on this being the path forward for the port.

In one of our weekly video meetings, Andreas mentioned that loading and saving of classdef objects as a possible issue to work on, mostly because it was a missing classdef feature that couldn’t be worked around easily.

Explanation of saving and loading in Octave

To give you a bit of background before I explain, if you create some workspace variables, etc. you can save these variables by calling something along the lines of save -FORMAT FILENAME.

The options for FORMAT are:

  • Native Octave formats, either text-based or binary
  • MAT files, either corresponding to v5 or v7 MAT files

However, before the summer started, classdef objects could not be loaded and saved.

Initially, I admit I was a bit skeptical to work on this issue, because Chebfun doesn’t really intimately rely on saving and loading of objects. It would be nice to have, but it wasn’t a reason for Chebfun to not work. However, while working on the loading and saving of classdef objects, it was actually the perfect bug for me to work on, because I got up to speed very quickly with (1) all classdef features, and (2) Octave internals, because saving of loading of classdefs touches all the classdef internals very deeply. So in the months of June and part of July, I spent a long time poking around at Octave load/save internals.

The result was introductory support of loading and saving of classdef objects. Some of the kinks still need to be ironed out. You can see the discussion on bug #45833 about how complex getting full saving/loading support is. A lot of the complexity comes from MATLAB’s poorly documented descriptions of how saving and loading works at a fine-grained level. Another source of complexity was that the native Octave file formats were designed to save simpler types like numeric arrays and structs, not complex objects. So lots of reverse-engineering and testing edge cases was needed.

Getting Chebfun working

Of course, the main thrust of the project. We’ve been measuring progress of Chebfun by counting the number of tests passed.

Basically, in the tests folder you have the following subfolders:

adchebfun       chebfun3t       chebtech2       misc            spinpref
ballfun         chebfun3v       classicfun      operatorBlock   spinpref2
ballfunv        chebgui         deltafun        singfun         spinpref3
bndfun          chebmatrix      diskfun         spherefun       spinprefsphere
cheb            chebop          diskfunv        spherefunv      spinscheme
chebfun         chebop2         domain          spinop          treeVar
chebfun2        chebpref        fun             spinop2         trigspec
chebfun2v       chebtech        functionalBlock spinop3         trigtech
chebfun3        chebtech1       linop           spinopsphere    unbndfun

Essentially, we’ve starting from basically 0 tests passing to:

Total number of tests:
1104
Number of successful tests:
576
Number of failed tests:
50
Number of crashed tests:
478

A failed test is one that executes without error, but produces an incorrect result. A crashed test is one that produces an interpreter error.

Qualitatively, 1D Chebfun is pretty good. There’s some annoying bugs, but generally it works well in most cases and fails fast if it doesn’t. You can run most of the Chebfun Guide without encountering errors, which feels pretty good.

Unfortunately, differential equation solvers are a bit of a ways away. Hopefully they will be working soon, but there’s some underlying Octave interpreter bugs that are causing all the tests to fail.

Overall, is this a success? I would say so! My opinion is that getting Chebfun working without an immediate crash was a large hurdle, and now that it’s semi-fixed, a lot of the remaining bugs will be easier to work around. There’s quite a lot of remaining crashed tests, but many of them have the same underlying cause, and generally only one individual test out of the usual 4 - 20 tests in a file will crash.

Patches for GNU Octave

Bug #67048: findobj with ‘tag’=[]. This was the initial patch I submitted before I was even accepted into GSoC. It fixs a very small issue with the findobj function. It was the first patch I submitted to Octave, before I was formally accepted into GSoC.

Bug #45833: support load/save of classdef objects. I’ve already discussed at length in an earlier section. This discussion (along with the discussion on Discourse about loading and saving) also contains the genesis of MAT file support for loading and saving classdef objects.

Bug #67311: Very bad slowdown of load(): Does it really count if I was the reason for this bug? I introduced it while working on load/save of classdef objects. In a nutshell, the problem was that every time a variable was being loaded from a save file to the workspace, Octave would check the type of the variable. In order to support classdef objects, I added a call to which to determine if the variable type was a classdef constructor. The offending line was

octave::__get_help_system__ ().which (typ, class_type);

which (ha!) is a function that searches the Octave path with the given name. This was a terrible idea, because which is a heavyweight user-facing function that allows you to search for anything in the Octave path. What would happen is, you’d have a save file with about ~100 or so variables to load that would take around 30 seconds to load. That’s a catastrophic performance hit, since it took less than 0.1 seconds to load beforehand.

The fix was quite simple, actually, I had to use the internal cdef_manager utility to find if the variable was a classdef, rather than using which. It was a bug that was fixed within three hours of being reported, so a crisis was successfully averted!

GNU Octave - Bugs: bug #67362, Subsref should resolve to property… [Savannah]. I talk about this bug in one of my Chebfun status reports. I pushed a fix myself, because the prospect of manually renaming a variable in hundreds of places sounded horrendous.

GNU Octave - Patches: patch #10537, Support for InferiorClasses… [Savannah]. Final patch I submitted before the end of the GSoC period. You can read more about it in my Chebfun status report.

Chebfun Patches

If you want to check the latest progress on Chebfun, check out this repository.

The following is a list of commits that were applied by myself to Chebfun during the GSoC period. The nature of this work is that many commits were either rolled back once they were fixed in core Octave, or they were superceded by better workarounds. Colin also commited many changes during this period: you can look at all the commits during the summer of 2025 on this branch.

* c9e452aea (HEAD -> gsoc_2025, origin/gsoc_2025, octave_dev) Rewrote README and added gsoc.md for final status report of GSoC 2025
* 4faac7d31 (origin/edit_octave_notes, edit_octave_notes) Updated octave_notes.md
* 5797dad8e Changed octave_notes to use Markdown
* 6f1cdac70 Revert "octave: TEMPORARY: remove the domain class and replace with domain.m"
* 04dbfed5c Turned vectorize off by default in chebop.
* dc33cc34b Disable tests that crash that Octave interpreter.
* d83eda024 Renamed filename resetPointValues to clearPointValues in order to match function name.
* 073c5da2f Changes to seedRNG.m by changing 'verLessThan' calls to 'compatible_verLessThan'.
* 2be39a0b8 Changes to plot.m by changing 'verLessThan' calls to 'compatible_verLessThan'.
* f663c4f23 Replaced 'fields' method with the 'fieldnames' method.
* fde15d655 Declare fun class as Abstract.
* 0988a0c7b Workaround for isequal precendence call.
* f1a6b203e Revert "octave: use static methods instead of class-related functions"
* 9ecedcaca Ignore this test for now, it crashes the interpreter.
* bea491edb Ignore these tests for now.
* 8a8531469 Changed verLessThan to compatible_verLessThan
* c6b1b0fc5 Added a new function to handle 'verLessThan('matlab', version)' calls.
* e3dc50141 Fix unintended behaviour making f a complex-valued chebfun.
* ca29a7908 Revert "octave: temporary workaround for f.funs{j}"
* 70b9c3fbe Revert "octave: TEMPORARY dumb hack: always return [-1, 1] for domain"
* cf7052d4f Added comma delimiter for cell array of anon functions.
* 3ffe9891b Revert "octave: workaround subsref and property fighting over "domain""
* 0d2c86de2 Revert "Workaround for subsref issue with domain"
* b6a9da520 Revert "Temp fix for 2*chebfun() to work"
* 52f428b50 Add method to check if Octave is being used
* 3e6c8d3bd Temp fix for 2*chebfun() to work
* 7b1460582 Workaround for subsref issue with domain
* 839da2ed2 Update octave_notes.txt
* cb59de187 resetPointValue: rename function to match filename

Bug Reports for GNU Octave

These are bugs I’ve reported that I didn’t submit a patch for. Some of them were fixed by others, some are still open at the time of writing.

Bug #67197: Class with abstract properties can be instantiated, but should not be able to be. An incompatibility between MATLAB and Octave regarding abstract classes. In short, MATLAB behaviour is the following: if even a single method or a property is labelled abstract, then the entire class is abstract. Octave doesn’t have the same semantics, which is a bug. Easy workaround though, you can just manually label the entire class as abstract.

Bug #67248: AddressSanitizer catches ‘container-overflow’ in svd.cc when running tests. To be honest, I had heard about C++ code sanitizers before this summer, but I never bothered to use one. What a huge mistake! Sanitizers are fantastic tools, they catch a legitimately huge class of memory errors. If you compile with Clang, it’s dead simple to use, just add -fsanitize=address to your compiler flags. This is just one of them that I encountered before someone else did, but using a sanitizer saved me an incredible amount of time. I highly recommend using sanitizers for pretty much every debug build you’ll ever do in a C/C++ codebase.

Bug #67258: Bad memory access when trying to integrate 1/sqrt(x) in ‘quadv.m’. The one bug that got away. It was automatically fixed when I updated the project dependencies, and now I’ll never know what caused it. Oh well.

Bug #67361: Classdef property and method should not have the same name. An incompatibility with MATLAB, and a source of many headaches in the Octave internals.

Bug #67348: Cell array construction of anonymous functions fails without comma delimiting. Probably the tiniest bug I could have reported. Essentially, MATLAB allows you to initialize a vector by writing

[ 1 2 3 4 ]

instead of putting a delimiter of some kind between the values, like a comma, which is used in other languages. It’s supposed to mimic writing a vector on a blackboard. But this feature got extended in two different ways. First, to cell arrays, which is a container that lets you mix different datatypes together, like so

{ 1 2.2 3 4 + 2i }

which looks horrible on the eyes, but it’s valid MATLAB/Octave. The second way this feature was extended was by means of allowing this lack of delimiters between non-numeric datatypes. So in MATLAB, you could write

{ @(x) cos(x) @(x) sin(x) }

(In MATLAB, @(x) … is the syntax for an anonymous/lambda function). Octave mostly supports this feature, but fails in the above anonymous function case. The workaround is hilariously simple: just put a comma! Still, it’s always a good thing to document the discrepancies between MATLAB and Octave.

Bug #67412: verLessThan(‘matlab’, …) should emit a warning rather than throw an error. A proposal that fell flat on it’s face. Let me give some context to explain the rational behind this proposal. In MATLAB code, you often see version checks like this

verLessThan('matlab', VER)

(As an aside, after R2023 it’s no longer recommended to check the MATLAB version this way). The pseudocode for the function behaviour looks something like this:

if toolbox exists
    if version_of_toolbox < VER
        return true
    else
        return false
else
    throw error

Straightforward, if you accept that MATLAB counts as an acceptible input for toolbox. Well, Octave doesn’t, because of course not, it cannot acknowledge the existence of MATLAB. I’m joking a bit. But, strictly speaking, if you accept that MATLAB is an acceptible first argument, you have to assign it a version. My thought is that MATLAB’s version on Octave is 0.0.0, because Octave is supposed to be feature compatible with the latest MATLAB, and every time it is not, it’s an incompatibility bug. Either Octave supports the feature that’s being distinguished, or it doesn’t, but checking on Octave whether MATLAB is less than some version is devoid of meaning. The real motivation for this proposal is that porting MATLAB code would be ever so slightly easier if Octave didn’t throw an error on this function call.

Bug #67413: Stacktrace from error should show class name along with function name. Essentially, a case that errors should contain more information than simply the name of the function where the error occured. Still a work in progress at the time of writing, but there’s some progress being made.

What I learned

Quite a bit.

On the programming side, I learned how to read (two!) giant codebases, one in C++ and one in MATLAB.

When I was contributing to Octave, I learned the following

When I was contributing to Chebfun, I learned the following:

On the more human side, I learned how to work effectively with others. I learned how to present my ideas and findings clearly, how to debate for my positions while being collaborative and open to feedback, and how to consolidate my knowledge into something sharable. Lastly, I learned how to jump into a new project and get up to speed quickly. I fully believe I can launch into new projects with a high degree of autonomy and confidence at this point.

Next Steps

I will co-maintain the Octave port of Chebfun with Colin. We will continue to develop the capabilities of Chebfun further, and I’ll continuously update the blog on the progress. Another possible avenue of approach may be to try to upstream our changes to the original Chebfun project; however, we have not decided if this is feasible yet.

Getting CI/CD working for Chebfun is a high priority task. Right now, most of the testing is done manually, and producing tarballs for releases is also done manually. This means setting up a Docker container with the latest Octave build, which does not exist as of now.

In core Octave, the rudimentary capabilities and the myriad of bugs regarding classdef arrays are a big issue; see this issue for a particularly bad case. This is tough becuase these sorts of issues cannot be worked around in Octave code. Fixing classdef arrays is a difficult undertaking, but one I hope to contribute to.

Loading and saving

Even after all the work put into loading and saving, it is unclear if the native Octave file formats should continue to be used. The three options going forward are:

Acknowledgements

I would like to thank my mentors, Colin B. Macdonald and Andreas Bertsatos, for their patient guidance and support throughout this project. They were kind enough to hear out my ideas, let me work in the direction that I thought was best, and they were always available to answer my questions. Their enthusiasm to see this project succeed was infectious, and I am very honored they entrusted me with this project. I learned a lot from both of them, and I am very grateful for their mentorship.

I would also like the thank the GNU Octave maintainers for their support, their willingness to hear out my ideas and review my patches, and of course for administering GSoC. In particular, I would like to thank John W. Eaton and Markus Mützel for hosting office hours and answering my questions, but there were many others who helped me along the way as well.

I would also like to thank Google for running the GSoC program and making this project possible.