Community round-up – container types and complex number libraries

While Software AG is busy adding features to Apama, the community is busy creating and publishing things as well. We maintain an index of the various community-created projects on GitHub. We hope that these community libraries and plug-ins can be useful for others and share them for people to use. Improvements and contributions are also very welcome.

In this blog post we’re going to look at a couple of the recent contributions to go up on the index, what they do and what future directions or contributions they would accept.

Container types library

Apama has a couple of built-in container types (sequence and dictionary). While these can be used to implement more complex APIs, and are relatively efficient, they don’t provide it directly. This library provides several more options, more are being worked on.

The library is hosted on GitHub and you can find the API documentation also hosted there.

The new container types:

Stack

A generic Last-In-First-Out container, storing objects as anys.

Stack s := Stack.create();
s.push(1);
s.push("hello world");
print s.pop().valueToString();

Queue

A generic First-In-First-Out container, storing objects as anys.

Queue s := Queue.create();
q.push(1);
q.push("hello world");
print q.pop().valueToString();

Heap

A Max/Min-value Heap object with configurable type comparators. Heaps are an efficient way to keep a semi-sorted data-structure where you can insert in any order and retrieve the first element. When creating a heap you also provide a function to compare items in the heap and provide an ordering between them. This function can work on any type. Integer and string comparators are provided, as is a comparator which will use an integer field on arbitrary event types to sort the events.

event E {
   integer id;
   string data;
}
Heap h := Heap.create(HeapIntegerFieldComparator("id", false));
h.push(E(15, "15"));
h.push(E(6, "6"));
h.push(E(12, "12"));
h.push(E(1, "1"));
h.push(E(18, "18"));
while h.size() > 0 {
    print (<E> h.pop()).data; // returns the data in the order 1 6 12 15 18
}

Heaps can also be created from an existing unordered sequence object, in which case it will create the heap in-place in the sequence and maintain the heap in the sequence:

sequence<any> data := [<any> 5, 1, 19, 6, 4, 11];
Heap h := Heap.heapify(data, HeapIntegerComparator(true));
while h.size() > 0 {
    print (<integer> h.pop()).toString(); // returns the data in the order 19, 11, 6, 5, 4, 1
}

FixedSizeCircularBuffer

A circular buffer which will remember the most recent fixed number of items in it, storing objects as anys.


FixedSizeCircularBuffer buf := FixedSizeCircularBuffer.create(10);
count := 0;
while count < 20 {
    buf.push(count);
    count := count + 1;
}
buf.push("Hello World");
print buf.get(0).toString(); // prints 10, the first 10 have been pushed out of the buffer

Future directions

The next data structures to work on are trees of various sorts. Binary trees, red-black trees. Other ideas welcome.

Complex numbers library

Apama provides mathematical functions such as trig functions on the float and decimal types. There is not, however, a built-in complex numbers type. This library provides a complex number type with similar mathematical functions implemented.

The library is hosted on GitHub and you can find the API documentation also hosted there.

Complex

Because the complex numbers are represented with events, rather than primitives, most of the functions come in two forms. One is a static function which takes the operands as arguments, does the calculation and returns a new Complex object. The second form, prefixed with ‘u’, is an instance method which takes the instance as the first operand and updates it in place. These latter methods also return a reference to the modified object for use in chains of in-place operations.

Complex c1 := Complex(3.1, 5.0); // 3.1 + 5.0i
Complex c2 := Complex.fromPolar(7.2, float.PI/2.0) // 7.2i
Complex c3 := Complex.add(c1, c2); // 3.1 + 12.2i
Complex c4 := c3.uexp().umultiplyReal(3.5).usqrt().usubtract(Complex.E()); // sqrt(3.5 * e^(3.1 + 12.2i)) - e

As well as simple addition and multiplication, the library also provides functions for complex trig functions, complex exponents, logarithms and powers. There are also statics to return useful constants such as e, pi etc.

Complex numbers are used for many physical descriptions such as 2d rotations, fluid dynamics, signal analysis and many other fields.

Quaternion

In addition to complex numbers, the library also provides support for calculations with quaternions. Quaternions are a real scalar part, plus a three dimensional vector part using the imaginary numbers i, j and k. Using the Quaternion type is just like using the Complex type above.

Quaternion q1 := Quaternion(1., 0.5, float.PI, 2.1); // 1 + 0.5i + PIj + 2.1k
Quaternion q2 := Quaternion.add(q1, Quaternion.fromRealFloat(2.)); // 3 + 0.5i + PIj + 2.1k
Quaternion q3 := q2.umultiply(q1); // etc

Quaternions are used to describe 3d rotations and other applied mathematics.

Future directions

Further options for numeric libraries include big numbers and matrices.

Summary

These are just a couple of the community activities going on outside of the official Software AG ecosystem. We hope they may prove useful. Please contact the author of the plugins via GitHub if you have any useful comments and as always feel free to ask questions via the apama tag on Stack Overflow.

Look out for the next blog post in this series,
Matt