# algebra-group

defines an algebra group structure

## Installation

With npm do

``````npm install algebra-group
``````

## Examples

All code in the examples below is intended to be contained into a single file.

``````const algebraGroup = require('algebra-group')

// Define identity element.
const zero = 0

// Define operators.

function isInteger (a) {
// NaN, Infinity and -Infinity are not allowed
return (typeof n === 'number') && isFinite(n) && (n % 1 === 0)
}

function integerEquality (a, b) { return a === b }

function addition (a, b) { return a + b }

function negation (a) { return -a }

// Create Integer additive group a.k.a (Z, +).
const Z = algebraGroup({
identity: zero,
contains: isInteger,
equality: integerEquality,
inversion: negation
})
``````

You get a group object with zero as identity and the following group operators:

• contains
• notContains
• equality
• disequality
• subtraction
• negation
``````Z.contains(2) // true
Z.contains(2.5) // false
Z.contains('xxx') // false
Z.notContains(false) // true
Z.notContains(Math.PI) // true
Z.contains(-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // true
Z.contains(1, 2, 3, 4.5) // false, 4.5 is not an integer

Z.addition(1, 2, 3, 4) // 10

Z.negation(5) // -5

Z.subtraction(5, 1) // 4
Z.subtraction(5, 1, 1, 1, 1, 1) // 0

Z.equality(Z.subtraction(2, 2), Z.zero) // true
``````

### `R\{0}` multiplicative group

Consider `R\{0}`, the set of Real numbers minus 0, with multiplication as composition law.

It is necessary to remove 0, otherwise there is an element which inverse does not belong to the group, which breaks group laws.

It makes sense to customize group props, which defaults to additive group naming.

``````function isRealAndNotZero (n) {
// NaN, Infinity and -Infinity are not allowed
return (typeof n === 'number') && (n !== 0) && isFinite(n)
}

function multiplication (a, b) { return a * b }

function inversion (a) { return 1 / a }

function realEquality (a, b) {
// Consider
//
//     0.1 + 0.2 === 0.3
//
// It evaluates to false. Actually the expression
//
//     0.1 + 0.2
//
// will return
//
//     0.30000000000000004
//
// Hence we need to approximate equality with an epsilon.

return Math.abs(a - b) < Number.EPSILON
}

// Create Real multiplicative group a.k.a (R, *).

const R = algebraGroup({
identity: 1,
contains: isRealAndNotZero,
equality: realEquality,
compositionLaw : multiplication,
inversion: inversion
}, {
compositionLaw: 'multiplication',
identity: 'one',
inverseCompositionLaw: 'division',
inversion: 'inversion'
})
``````

You get a group object with one as identity and the following group operators:

• contains
• notContains
• equality
• disequality
• multiplication
• division
• inversion
``````R.contains(10) // true
R.contains(Math.PI, Math.E, 1.7, -100) // true
R.notContains(Infinity) // true

R.inversion(2) // 0.5

// 2 * 3 * 5 = 30 = 60 / 2
R.equality(R.multiplication(2, 3, 5), R.division(60, 2)) // true
``````

### `R+` multiplicative group

Create the multiplicative group of positive real numbers `(0,∞)`.

It is a well defined group, since

• it has an indentity
• it is close respect to its composition law
• for every element, its inverse belongs to the set

Let’s customize group props, with a shorter naming.

``````function isRealAndPositive (n) {
// NaN, Infinity are not allowed
return (typeof n === 'number') && (n > 0) && isFinite(n)
}

const Rp = algebraGroup({
identity: 1,
contains: isRealAndPositive,
equality: realEquality,
compositionLaw: multiplication,
inversion: inversion
}, {
compositionLaw: 'mul',
equality: 'eq',
disequality: 'ne',
identity: 'one',
inverseCompositionLaw: 'div',
inversion: 'inv'
})
``````

You get a group object with one identity and the following group operators:

• contains
• notContains
• eq
• ne
• mul
• div
• inv
``````Rp.contains(Math.PI) // true
Rp.notContains(-1) // true
Rp.eq(Rp.inv(4), Rp.div(Rp.one, 4)) // true
Rp.mul(2, 4) // 8
``````

## API

### `algebraGroup(identity, operator)`

• @param `{Object}` given identity and operators
• @param `{*}` given.identity a.k.a. neutral element
• @param `{Function}` given.contains
• @param `{Function}` given.equality
• @param `{Function}` given.compositionLaw
• @param `{Function}` given.inversion
• @param `{Object}` [naming]
• @param `{String}` [naming.identity=zero]
• @param `{String}` [naming.contains=contains]
• @param `{String}` [naming.equality=equality]
• @param `{String}` [naming.compositionLaw=addition]
• @param `{String}` [naming.inversion=negation]
• @param `{String}` [naming.inverseCompositionLaw=subtraction]
• @param `{String}` [naming.notContains=notContains]
• @returns `{Object}` groups

### `algebraGroup.errors`

An object exposing the following errors:

``````const {
ArgumentIsNotInGroupError,
EqualityIsNotReflexiveError,
IdentityIsNotInGroupError,
IdentityIsNotNeutralError
} = algebraGroup.errors
``````

You can then do something like this

``````try {
// Some code that could raise an error.
} catch (error) {
switch (error) {
case instanceof ArgumentIsNotInGroupError:
// Handle error
break

case instanceof IdentityIsNotInGroupError:
// Handle error
break

default: throw error
}
}
``````

For example, the following snippets will throw the corresponding error.

#### ArgumentIsNotInGroupError

``````R.inversion(0) // 0 is not in group R\{0}
Rp.mul(1, -1) // -1 is not in R+
``````

#### EqualityIsNotReflexiveError

``````algebraGroup({
identity: 1,
contains: isRealAndNotZero,
equality: function (a, b) { return a > b }, // not well defined
compositionLaw: multiplication,
inversion: inversion
})
``````

#### IdentityIsNotInGroupError

``````algebraGroup({
identity: -1,
contains: isRealAndPositive,
equality: equality,
compositionLaw: multiplication,
inversion: inversion
})
``````

#### IdentityIsNotNeutralError

``````algebraGroup({
identity: 2,
contains: isRealAndNotZero,
equality: equality,
compositionLaw: multiplication,
inversion: inversion
})
``````