Tag Archives: language

Introducing ILNumerics.ONAL – The Open Numerical Algorithm Language for .NET

Introducing ILNumerics.ONAL

We are happy to announce the public availability of ILNumerics.ONAL, the open-source reference implementation of the ONAL (Open Numerical Algorithm Language) standard for .NET.

ONAL defines a standardized numerical array language for .NET, designed to provide MATLAB- and NumPy-compatible expressiveness while remaining stable, vendor-neutral, and compiler-friendly.

The source code is available on GitHub, and NuGet packages are published on nuget.org.

Technical Highlights

ILNumerics.ONAL provides a complete, production-ready environment for numerical computing in C# and Visual Basic. The project is derived from the commercial ILNumerics technology stack, which has been used successfully in thousands of industrial and academic applications for more than a decade.

The ONAL language library includes:

  • multidimensional dense arrays
  • MATLAB- and NumPy-compatible array semantics
  • broadcasting and advanced indexing
  • mutable arrays with thread-safe semantics
  • complex numbers as first-class numeric types
  • cells and heterogeneous containers
  • integration-friendly native buffer storage
  • linear algebra and FFT functionality based on robust LAPACK implementations automatically translated from the official Netlib FORTRAN sources
  • a comprehensive set of mathematical, elementary, and trigonometric functions
  • Visual Studio debugger integration, including array visualizers for convenient inspection of numerical data

The implementation focuses deliberately on correctness, robustness, and numerical language semantics. Performance-related APIs and execution details are intentionally kept out of the programming model.

The code base is accompanied by a comprehensive suite of roughly 2000 unit tests.

Open Source and Why It Matters

We decided to open-source the ONAL language core in 2026 in response to a problem we have observed for many years across both industry and research: the uncontrolled growth of custom in-house math libraries.

In the absence of a comprehensive, vendor-neutral numerical foundation for .NET, many organizations ended up building and maintaining their own array and math infrastructures. The result was often duplicated effort, fragmented semantics, difficult maintenance, compatibility issues, and long-term dependency risks.

Too many of these libraries eventually accumulated quirky APIs, legacy design constraints, performance-driven low-level details leaking into user code, poor maintainability—and, ironically, disappointing performance.

ILNumerics.ONAL aims to provide a stable and open alternative: a standardized numerical language foundation that remains fully usable without proprietary execution engines or vendor-specific runtimes.

Users keep full ownership of their algorithms and numerical IP, while benefiting from a mature and actively maintained implementation.

The Larger ILNumerics Ecosystem

ILNumerics.ONAL represents the core language layer of the broader ILNumerics ecosystem.

Algorithms written against the ONAL standard execute directly on .NET with reliable baseline performance. When higher performance is required, ONAL-compatible compilers—such as the ILNumerics Accelerator Compiler—can transparently apply advanced optimization techniques including:

  • automatic parallelization
  • graph optimization
  • array pipelining
  • SIMD vectorization
  • heterogeneous CPU/GPU scheduling
  • kernel fusion

ILNumerics.Computing serves as a fully compatible high-performance execution layer for ONAL-based algorithms. Existing code can often be accelerated simply by changing a package reference, without rewriting algorithms or introducing parallelization-specific code.

In practice, this frequently outperforms weeks or months of manual optimization work involving threading, vectorization, memory management, and hardware tuning.

At the same time, projects gain access to the broader ILNumerics ecosystem, including advanced visualization systems, charting components, debugger tooling, and domain-specific extensions.

This separation allows the numerical language itself to remain stable, open, and vendor-neutral, while execution technology and tooling continue to evolve independently.

In many ways, ILNumerics.ONAL can be seen as the semantic core of ILNumerics.Computing, separated from all performance-induced API complexity and execution-specific implementation details. It provides a clean and stable foundation for numerical algorithms today, while preserving a straightforward path toward high-performance execution whenever needed.

Make sure to check out the project and get involved. Contributions, discussions, and feedback are very welcome.

GitHub: https://github.com/ilnumerics/ILNumerics.ONAL
Nuget: https://www.nuget.org/packages/ILNumerics.ONAL

 

 

ILNumerics Language Features: Limitations for C#, Part II: Compound operators and ILArray

A while ago I blogged about why the CSharp var keyword cannot be used with local ILNumerics arrays (ILArray<T>, ILCell, ILLogical). This post is about the other one of the two main limitations on C# language features in ILNumerics: the use of compound operators in conjunction with ILArray<T>. In the online documentation we state the rule as follows:

The following features of the C# language are not compatible with the memory management of ILNumerics and its use is not supported:

  • The C# var keyword in conjunction with any ILNumerics array types, and
  • Any compound operator, like +=, -=, /=, *= a.s.o. Exactly spoken, these operators are not allowed in conjunction with the indexer on arrays. So A += 1; is allowed. A[0] += 1; is not!

Let’s take a closer look at the second rule. Most developers think of compound operators as being just syntactic sugar for some common expressions:

int i = 1;
i += 2;

… would simply expand to:

int i = 1;
i  = i + 2; 

For such simple types like an integer variable the actual effect will be indistinguishable from that expectation. However, compound operators introduce a lot more than that. Back in his times at Microsoft, Eric Lippert blogged about those subtleties. The article is worth reading for a deep understanding of all side effects. In the following, we will focus on the single fact, which becomes important in conjunction with ILNumerics arrays: when used with a compound operator, i in the example above is only evaluated once! In difference to that, in i = i + 2, i is evaluated twice.

Evaluating an int does not cause any side effects. However, if used on more complex types, the evaluation may does cause side effects. An expression like the following:

ILArray<double> A = 1;
A += 2;

… evaluates to something similiar to this:

ILArray<double> A = 1;
A = (ILArray<double>)(A + 2); 

There is nothing wrong with that! A += 2 will work as expected. Problems arise, if we include indexers on A:

ILArray<double> A = ILMath.rand(1,10);
A[0] += 2;
// this transforms to something similar to the following: 
var receiver = A; 
var index = (ILRetArray<double>)0;
receiver[index] = receiver[index] + 2; 

In order to understand what exactly is going on here, we need to take a look at the definition of indexers on ILArray:

public ILRetArray<ElementType> this[params ILBaseArray[] range] { ... 

The indexer expects a variable length array of ILBaseArray. This gives most flexibility for defining subarrays in ILNumerics. Indexers allow not only scalars of builtin system types as in our example, but arbitrary ILArray and string definitions. In the expression A[0], 0 is implicitly converted to a scalar ILNumerics array before the indexer is invoked. Thus, a temporary array is created as argument. Keep in mind, due to the memory management of ILNumerics, all such implicitly created temporary arrays are immediately disposed off after the first use.

Since both, the indexing expression 0 and the object where the indexer is defined for (i.e.: A) are evaluated only once, we run into a problem: index is needed twice. At first, it is used to acquire the subarray at receiver[index]. The indexer get { ...} function is used for that. Once it returns, all input arguments are disposed – an important foundation of ILNumerics memory efficency! Therefore, if we invoke the index setter function with the same index variable, it will find the array being disposed already – and throws an exception.

It would certainly be possible to circumvent that behavior by converting scalar system types to ILArray instead of ILRetArray:

ILArray A = ...;
A[(ILArray)0] += 2;

However, the much less expressive syntax aside, this would not solve our problem in general either. The reason lies in the flexibility required for the indexer arguments. The user must manually ensure, all arguments in the indexer argument list are of some non-volatile array type. Casting to ILArray<T> might be an option in some situations. However, in general, compound operators require much more attention due to the efficient memory management in ILNumerics. We considered the risk of failing to provide only non-volatile arguments too high. So we decided not to support compound operators at all.

See: General Rules for ILNumerics, Function Rules, Subarrays