node package manager

Introducing npm Enterprise add-ons. Integrate third-party dev tools into npm…

algebra

means completeness and balancing, from the Arabic word الجبر

algebra

Vectors, Matrices; Real, Complex, Quaternion; custom groups and rings for Node.js

New: checkout matrices and vectors made of strings, with cyclic algebra.

algebra is under development, but API should not change until version 1.0.

I am currently adding more tests and examples to achieve a stable version.

Many functionalities of previous versions are now in separated atomic packages:

  • Real, Complex, Quaternion, Octonion numbers.
  • Vector and Matrix spaces over any field (included Real numbers, of course :).
  • Expressive syntax.
  • Everything is a Tensor.
  • Immutable objects.
  • math blog with articles explaining algebra concepts and practical examples. I started blogging about math hoping it can help other people learning about the Queen of Science.

With npm do

npm install algebra

With bower do

bower install algebra

or use a CDN adding this to your HTML page

<script src="https://cdn.rawgit.com/fibo/algebra/master/dist/algebra.min.js"></script>

This is a 60 seconds tutorial to get your hands dirty with algebra.

First of all, import algebra package.

var algebra = require('algebra')

All code in the examples below should be contained into a single file, like test/quickStart.js.

Use the Real numbers as scalars.

var R = algebra.Real

Every operator is implemented both as a static function and as an object method.

Static operators return raw data, while class methods return object instances.

Use static addition operator to add three numbers.

R.add(1, 2, 3) // 1 + 2 + 3 = 6 

Create two real number objects: x = 2, y = -2

var x = new R(2)
var y = new R(-2)

The value r is the result of x multiplied by y.

// 2 * (-2) = -4 
var r = x.mul(y)
 
// Scalar { data: -4 } 
 
// x and y are not changed 
x.data // 2 
y.data // -2 

Raw numbers are coerced, operators can be chained when it makes sense. Of course you can reassign x, for example, x value will be 0.1: x -> x + 3 -> x * 2 -> x ^-1

// ((2 + 3) * 2)^(-1) = 0.1 
= x.add(3).mul(2).inv()
 
// Scalar { data: 0.1 } 

Comparison operators equal and notEqual are available, but they cannot be chained.

x.equal(0.1) // true 
x.notEqual(Math.PI) // true 

You can also play with Complexes.

var C = algebra.Complex
 
var z1 = new C([1, 2])
var z2 = new C([3, 4])
 
z1 = z1.mul(z2)
 
z1 // Scalar { data: [-5, 10] } 
 
z1 = z1.conj().mul([2, 0])
 
z1.data // [-10, -20] 

Create vector space of dimension 2 over Reals.

var R2 = algebra.VectorSpace(R)(2)

Create two vectors and add them.

var v1 = new R2([0, 1])
var v2 = new R2([1, -2])
 
// v1 -> v1 + v2 -> [0, 1] + [1, -2] = [1, -1] 
v1 = v1.add(v2)
 
v1 // Vector { data: [1, -1] } 

Create space of matrices 3 x 2 over Reals.

var R3x2 = algebra.MatrixSpace(R)(3, 2)

Create a matrix.

//       | 1 1 |
//  m1 = | 0 1 |
//       | 1 0 |
//
var m1 = new R3x2([1, 1,
                   0, 1,
                   1, 0])

Multiply m1 by v1, the result is a vector v3 with dimension 3. In fact we are multiplying a 3 x 2 matrix by a 2 dimensional vector, but v1 is traited as a column vector so it is like a 2 x 1 matrix.

Then, following the row by column multiplication law we have

//  3 x 2  by  2 x 1  which gives a   3 x 1 
//      ↑      ↑ 
//      +------+----→  by removing the middle indices. 
// 
//                   | 1 1 | 
//    v3 = m1 * v1 = | 0 1 | * [1 , -1] = [0, -1, 1] 
//                   | 1 0 | 
 
var v3 = m1.mul(v1)
 
v3.data // [0, -1, 1] 

Let's try with two square matrices 2 x 2.

var R2x2 = algebra.MatrixSpace(R)(2, 2)
 
var m2 = new R2x2([1, 0,
                   0, 2])
 
var m3 = new R2x2([0, -1,
                   1, 0])
 
m2 = m2.mul(m3)
 
m2 // Matrix { data: [0, -1, 2, 0] }

Since m2 is a square matrix we can calculate its determinant.

m2.determinant // Scalar { data: 2 } 

All operators are implemented as static methods and as object methods. In both cases, operands are coerced to raw data. As an example, consider addition of vectors in a plane.

var R2 = algebra.R2
 
var vector1 = new R2([1, 2])
var vector2 = new R2([3, 4])

The following static methods, give the same result: [4, 6].

R2.addition(vector1, [3, 4])
R2.addition([1, 2], vector2)
R2.addition(vector1, vector2)

The following object methods, give the same result: a vector instance with data [4, 6].

var vector3 = vector1.addition([3, 4])
var vector4 = vector1.addition(vector2)
 
R2.equal(vector3, vector4) // true 

Operators can be chained and accept multiple arguments when it makes sense.

vector1.addition(vector1, vector1).equality([4, 6]) // true 

Objects are immutable

vector1.data // still [1, 2] 

Create an algebra cyclic ring, by passing its elements. The elements are provided as a string or an array, which lenght must be a prime number. This is necessary, otherwise the result would be a wild land where you can find zero divisor beasts.

Let's create a cyclic ring containing lower case letters, numbers and the blank char. How many are they? They are 26 + 10 + 1 = 37, that is prime! We like it.

var Cyclic = algebra.Cyclic
 
// The elements String or Array length must be prime. 
var elements = ' abcdefghijklmnopqrstuvwyxz0123456789'
 
var Alphanum = Cyclic(elements)

Operators derive from modular arithmetic

var a = new Alphanum('a')
 
Alphanum.addition('a', 'b') // 'c' 

You can also create element instances, and do any kind of operations.

var x = new Alphanum('a')
 
var y = x.add('c', 'a', 't')
         .mul('i', 's')
         .add('o', 'n')
         .sub('t', 'h', 'e')
         .div('t', 'a', 'b', 'l', 'e')
 
y.data // 's' 

Yes, they are scalars so you can build vector or matrix spaces on top of them.

var VectorStrings2 = algebra.VectorSpace(Alphanum)(2)
var MatrixStrings2x2 = algebra.MatrixSpace(Alphanum)(2)
 
var vectorOfStrings = new VectorStrings2(['o', 'k'])
var matrixOfStrings = new MatrixStrings2x2(['c', 'o',
                                            'o', 'l'])
 
matrixOfStrings.mul(vectorOfStrings).data // ['x', 'x' 
                                          //  'x', 'x'] 

A composition algebra is one of ℝ, ℂ, ℍ, O: Real, Complex, Quaternion, Octonion. A generic function is provided to iterate the Cayley-Dickson construction over any field.

  • num can be 1, 2, 4 or 8

Let's use for example the src/booleanField which exports an object with all the stuff needed by algebra-ring npm package.

var CompositionAlgebra = algebra.CompositionAlgebra
 
var booleanField = require('algebra/src/booleanField')
 
var Bool = CompositionAlgebra(booleanField)
 
Bool.contains(true) // true 
Bool.contains(1) // false 
 
Bool.addition(true, false) // true 
 
var t = new Bool(true)
t.negation().data // false 

Not so exciting, let's build something more interesting. Let's pass a second parameter, that is used to build a Composition algebra over the given field. It is something experimental also for me, right now I am writing this but I still do not know how it will behave. My idea is that

A byte is an octonion of booleans

Maybe we can discover some new byte operator, taken from octonion rich algebra structure.

// n must be a power of two
// TODO var Byte = CompositionAlgebra(boolean, 8)

It is always 0 for scalars, see also tensor order.

Inherits everything from Scalar.

var Real = algebra.Real
 
Real.addition(1, 2) // 3 
 
var pi = new Real(Math.PI)
var twoPi = pi.mul(2)
 
Real.subtraction(twoPi, 2 * Math.PI) // 0 

Inherits everything from Scalar.

var Complex = algebra.Complex
 
var complex1 = new Complex([1, 2])
 
complex1.conjugation() // Complex { data: [1, -2] } 

Inherits everything from Scalar.

Inherits everything from Scalar.

The real line.

It is in alias of Real.

var R = algebra.R

The real plane.

var R2 = algebra.R2

It is in alias of VectorSpace(Real)(2).

The real space.

var R3 = algebra.R3

It is in alias of VectorSpace(Real)(3).

Real square matrices of rank 2.

var R2x2 = algebra.R2x2

It is in alias of MatrixSpace(Real)(2).

The complex numbers.

It is in alias of Complex.

var C = algebra.C

Usually it is used the H in honour of Sir Hamilton.

It is in alias of Quaternion.

var H = algebra.H

Inherits everything from Tensor.

R2.dimension // 2 
var vector = new R2([1, 1])
 
vector.dimension // 2 
R2.addition([2, 1], [1, 2]) // [3, 3] 
var vector1 = new R2([2, 1])
var vector2 = new R2([2, 2])
 
var vector3 = vector1.addition(vector2)
 
vector3 // Vector { data: [4, 3] } 

It is defined only in dimension three. See Cross product on wikipedia.

R3.crossProduct([3, -3, 1], [4, 9, 2]) // [-15, 2, 39] 
var vector1 = new R3([3, -3, 1])
var vector2 = new R3([4, 9, 2])
 
var vector3 = vector1.crossProduct(vector2)
 
vector3 // Vector { data: [-15, 2, 39] } 

Inherits everything from Tensor.

It is defined only for square matrices which determinant is not zero.

It is defined only for square matrices.

It represents the number of varying indices.

  • A scalar has order 0.
  • A vector has order 1.
  • A matrix has order 2.
var T2x2x2 = TensorSpace(Real)([2, 2, 2])
 
var tensor1 = new T2x2x2([1, 2, 3, 4, 5, 6, 7, 8])
var tensor2 = new T2x2x2([2, 3, 4, 5, 6, 7, 8, 9])
T2x2x2.equality(tensor1, tensor1) // true 
T2x2x2.equality(tensor1, tensor2) // false 
tensor1.equality(tensor1) // true 
tensor2.equality(tensor2) // false 

MIT