Please read carefully parts (1), (2) and (3) to use this code. Parts (4) and (5) contain more detailed explanations.
In the article
[1] X. GarcĂa-MartĂnez, M. Tsishyn, T. Van der Linden and C. Vienne, Algebras with representable representations
we have encountered the need to determine a system of equations that is used to complete the proof of one of the main results. The inconsistency of this system proves that the result is valid. The computations required to arrive to this system of equations are, in a certain extent, repetitive and long enough to convince us that the best way to obtain the equations is by the use of a computer.
So, the purpose of this project is to generate the system of equations used in [1]. This project is written is a such way that anyone can replicate our computations and verify the correctness of this code. We also did our best to make the code, or at least its usage, understandable for those who are less familiar with programming.
This project is written in JavaScript, version 6 (ES6). JavaScript may not be the usual choice for this kind of algebraic computations. Languages such as Wolfram Mathematica are more adapted to symbolic manipulation of systems of equations. However, we chose to use JavaScript for the two following reasons:
- the algebraic structures we have to manipulate are very specific to this article, and we wanted to keep full control of what exactly the code is doing, to be completely sure of the result;
- the use of JavaScript allows anyone to test the code: no need for a license.
The purpose of this code is to generate a specific type of equations obtained from a specific type of expressions on specific algebraic structures, as described in the article [1]. So, there is absolutely no guarantee that it will give correct results in any other context. Knowing that, this code should not be used for any other purpose than the generation of equations in the context of the article [1], save by users who are totally aware of what they are doing.
In (2.1), we explain two ways this code can be run:
- in an on-line JavaScript editor;
- by executing a JavaScript project locally on your computer by means of Node.js, a classical way to execute JS files.
The first option does not require any modification of the code files. In the second case, some lines must be uncommented, in order to choose the way the output is presented.
In (2.2), we explain how the code can be used to obtain the set of equations in question. Furthermore, users can themselves obtain the equations they want by modifying or adding lines of code in the right place.
We adapted the code to two different environments.
2.1.1) On-line execution
The simplest way: Without any required installation on your computer, you can simply copy and paste the content of the file 'JScode.txt' (folder './online-execution/') in any JavaScript on-line editor (such as for instance 'https://playcode.io/online-javascript-editor'). Then, the system of equations will be displayed in the terminal.
2.1.2) Execution in Node.js
For 'Node.js' users, to run JavaScript locally on your computer, you first need to install Node.js. Then you can execute the content of the folder './script-for-node/' to obtain the results.
- The file 'script.js' defines the main code needed to obtain the equations from a given expression.
- The file 'usage.js' shows how to use the code from 'script.js'
- The file 'results.js' defines the eight expressions
$e_1$ , ...,$e_8$ and uses 'script.js' to obtain the wanted system of expressions.
To obtain the results, first uncomment the relevant lines in the file 'results.js', then execute it in the folder './script-for-node/', using the command line as follows.
node results.js
Once it is clear how to execute the code, here is a short explanation of the part that leads to the system of equations in question. This code is found in the following place:
- with (2.1.1): at the end of the text document './online-execution/JScode.txt';
- with (2.1.2): in the file './script-for-node/results.js'.
First, we define k
the unit of the field
const k = new Field('1');
Then, we define a1
, a2
and a3
as the three elements
const a1 = new Action(1), a2 = new Action(2), a3 = new Action(3);
Then, we define the monomial element X
that represents
const X = new Monomial({K: k, letter: 1, ind: [], exp: []});
Then, we define the expression from which we want to derive the equations. For example [[[a1,a2], a3], X]
represents
const myExpression = new Expression([[[a1,a2], a3], X])
Finally, to obtain the polynomial .equations()
of the class Expression
.
let polynomial = myExpression.equations()
We can display the whole polynomial
console.log(polynomial.read)
Or we can display the equations on myExpression
as
polynomial.value.forEach( v => {
console.log(v.value.K.value);
});
More detailed usage of the code is explained in './script-for-node/usage.js' and in part (5).
The folder './results/' contains two files:
- 'results.txt': a text file whose lines represent the equations on
$K$ that are equal to zero obtained from the eight expressions$e_1$ , ...,$e_8$ . - 'results.json': a JSON (JavaScript Object Notations) file, which is an object that gives all the equations together with the information from which expression each equation comes, as well as which base vector it is the coefficient of.
A complete and rigorous theoretical context of this code is explained in [1]. However, let us take some lines to explain the main idea of what the code computes from a more theoretical point of view.
Let us consider a field
where
Now, we define an action of three elements
for any
Now we consider the eight following algebraic expressions:
and
Note that the expressions
Then, each of these expressions
where
Thus we obtain a system of equations on
For those who want to play with the code, test the code, or verify its correctness, here is a more detailed explanation on how to use it and how it works.
This code defines five classes (Field, Action, Monomial, Polynomial and Expression) in the programming language JavaScript (version ES6). Each of these classes gives access to at least its '.value', its '.type' and its '.read' (which is an easy human readable version of its value) by using:
myElement.value
: gives the value that defines the element;
myElement.type
: gives a string that defines its class as 'field', 'action', 'monomial', 'polynomial' or 'expression';
myElement.read
: gives a human readable string that represents the value of the object.
Note that, unless this is specified, each method of each class will not change the content of the object on which it is applied; instead, it gives a new object as output.
An element of this class is an element
Initialization: with non-empty string or nothing (default value is '1'): myFieldElement = new Field(myString)
The element
Supports internal addition, product and negative:
Field.prototype.add(myFieldElement1, myFieldElement2)
Field.prototype.prod(myFieldElement1, myFieldElement2)
Field.prototype.negative(myFieldElement)
or myFieldElement.negative()
Type: myFieldElement.type
gives the string 'field';
Value:myFieldElement.value
gives a string that defines the value of the field element (which is a string composed of the symbols '(', ')', '+', '-', ' * ', '1', '0' and literal elements);
Read: myFieldElement.read
in the case of field elements, this is equivalent to myFieldElement.value
.
Usage
var k1 = new Field('mu1'); // declare new field element with value mu1
var k2 = new Field('mu2'); // declare new field element with value mu2
var unit = new Field(); // declare the unit element in the field ('1')
k1 = Field.prototype.prod(k1, k2) // compute the product of two field elements
k1 = Field.prototype.sum(k1, k1) // compute the sum of two field elements
k1 = Field.prototype.prod(k2, k1) // compute the product of two field elements
k1 = k1.negative() // compute the negative of a field element
console.log(k1.value) // k1 = -((mu2*((mu1*mu2)+(mu1*mu2))))
An element of this class is an element
Initialization: with a numeric element that is
Notation from the paper:
Type: myActionsElement.type
gives the string 'action';
Value:myActionElement.value
gives the number
Read: myActionElement.read
displays the string 'b', 'b*' or 'b**' depending on the value of the action.
Usage
var action = new Action(2) // initialize an action element
console.log(action.value) // 2 display the value of the action by 1, 2 or 3
console.log(action.read) // b* display the value of the action by 'b', 'b*' or 'b**'
An element of this class is an element that defines a monomial in the algebra
Initialization: with an object that possess properties K
, letter
, ind
and exp
. The value of K
is an element of the class Field, the value of letter
is a number among ind
is an array of elements that are numbers among exp
is an array of elements that are among the strings 'r' and 'l'. The lengths of the arrays ind
and exp
have to be the value of letter
minus one. The letter
values symbolize the notations of the article [1] as follows:
For example the monomial element
var k = new Field('mu1');
var value = {K: k, letter: 3, ind: [1,3], exp: ['r', 'l']};
var a = new Monomial(value);
The value of the zero element {K: '0', letter: 1, ind: [], exp: []}
. Any different notation of the zero element
Scalar multiplication by a field element:
Monomial.prototype.scalarMult(myFieldElement, myMonomialElement)
Action (left or right) by an action element:
Monomial.prototype.action(myActionElement, myMonomialElement)
(left action)
Data access:
myMonomialElement.K;
myMonomialElement.letter;
myMonomialElement.ind;
myMonomialElement.exp;
Type: myMonomialElement.type
gives the string 'monomial'.
Value:myMonomialElement.value
is an object that contains properties K
, letter
, ind
and exp
.
Read: myMonomialElement.read
gives a human readable string representation of the monomial element. For example,
Base Vector: The method myMonomialElement.baseVector
gives a string that represents the base vector of the monomial. For examples
Read expression: myMonomialElement.readExpression
gives a string that represents how the base vector of the monomial is obtained by actions on the element
Default Values: We can access the element
var zero = Monomial.prototype.zero;
var X = Monomial prototype.x;
Usage
var k1 = new Field('1'); // create a new field element
var k2 = new Field('mu'); // create a new field element
var action = new Action(3); // initialize an action element
var value = { // this kind of objects is used to initialize monomial element
K: k1, // must contain a field element in .K
letter: 3, // must contain a numeric element of 1, 2 , 3 or 4 in .letter (X => 1, Y => 2, Z => 3, T => 4)
ind: ['r','r'], // must contain an array of string 'l' or 'r' in .ind ('l' for left and 'r' for right)
exp: [1,2] // must contain an array of integers between 1, 2 and 3 in .exp
};
var a = new Monomial(value); // initialize a monomial element
console.log(a.read) // Z12rr display the value of the monomial
a = Monomial.prototype.action(action, a) // right action
console.log(a.read) // T123rrl
a = Monomial.prototype.scalarMult(k2, a) // scalar multiplication of a monomial by a field element
console.log(a.read) // (mu)*T123rrl
console.log(a.baseVector) // T123rrl Display the base vector of the monomial (monomial without its field coefficient)
console.log(a.isZero()) // false Tell if a monomial is equal to zero
console.log(a.readExpression) // (b**((Xb)b*)) Read the expression from which the base vector of this element is obtained by action on the X element
An element of this class is an element that defines a polynomial (can be a monomial too) in the algebra
Initialization: with an array of monomial objects (can be empty)
Add: the '.add()' method adds an array of monomials to the initial polynomial object. Note that this method modifies the initial object.
Type: myPolynomialElement.type
gives the string 'polynomial'
Value:myPolynomialElement.value
is a map that maps the string that represents the base vector of a monomial (for example 'Z12rl') to the value of the monomial in this base vector.
Read: myPolynomialElement.read
output an easy readable string that represents the polynomial element
Usage
var k = new Field('mu'); // initialize a field object
var a1 = new Monomial({K: k, letter: 3, ind: ['r','r'], exp: [1,2]}); // initialize a monomial object
var a2 = Monomial.prototype.x; // initialize another monomial object by using a default value (the monomial is X)
var a3 = Monomial.prototype.zero; // initialize another monomial object by using a default value (the monomial is 0)
var p = new Polynomial([a1, a2, a3]); // initialize a polynomial object
p.add([a2, a1, a1, a1, a3]) // add monomials to the initial polynomial
console.log(p.read) // (mu+mu+mu+mu)*Z12rr + (1+1)*X
The class Expression is made to carry the algebraic expressions that will lead to the system of equations used in the article [1].
Initialization: The expressions that are acceptable in the class Expression are:
- Degree 3: Any expression that can be obtained by computing the expression
$(X_1 \cdot a_1)\cdot a_2$ where$X_1$ is a monomial of the algebra$A$ and$a_1$ and$a_2$ are actions. - Degree 4: Any expression that can be obtained by computing the expression
$((a_1 \cdot a_2) \cdot a_3) \cdot X_1$ where$X_1$ is a monomial of the algebra$A$ and$a_1$ ,$a_2$ and$a_3$ are actions.
It can be initialized with degree 3 or degree 4 algebraic expressions such as [[X, a1], a2]
where X
is a Monomial element, and a1
and a2
are Action elements. The order of the operations is defined by how the arrays of objects are nested.
For example we can initialize an expression element $((b \cdot b') \cdot b'') \cdot (\mu_{1}X) $ as:
var X = new Monomial({K: new Field('mu1'), letter: 1, ind: [], exp: []}); // initialize the monomial element
var a1 = new Action(1), a2 = new Action(2), a3 = new Action(3); // initialize the action elements
var myExpression = new Expression([[[a1, a2], a3], X]);
Equations:
Given an expression object (of degree 3 or 4), this method expands it in the way that is described in the article [1] to obtain a system of polynomials on
myExpression.equations();
Degree: myExpression.degree
gives 3 or 4 that represents the number of factors in the expression;
Type: myExpression.type
gives the string 'expression';
Value: myExpression.value
is nested arrays of objects containing Monomial or Action objects;
Read: myExpression.read
give a human readable string that represents the expression.
Product: Remark: this method can be applied on any nested arrays of Monomial, Field and Action objects, not only on the particular case of class Expression objects.
Recursive function that solves any possible combinations on products that are among scalar multiplication on
Expression.prototype.product([k1,[[k2, b2, X], b1]]);
Note however that products of two Action elements or two Monomial elements are not defined and so the output is an error.
lambda/mu-rules:
Remark: this method can be applied to any object of the form [X,[Y,Z]]
or [[X,Y],Z]
where X
, Y
and Z
are any JS objects.
For Expression.prototype.identity([[X,Y],Z])
, output is [[mu1, exp1], ..., [m8, exp8]]
.
For Expression.prototype.identity([X,[Y,Z]])
, output is [[lambda1, exp1], ..., [lambda8, exp8]]
.
Where mu1
, ..., mu8
, lambda1
, ..., lambda8
are Field elements with values 'mu1', ..., 'lambda8'. Furthermore, exp1
to exp8
are different rearrangements of X
, Y
and Z
as defined by the lambda/mu-rules of [1]. So the main array of the output represents a sum.
We can add to the method '.identity()' a second argument of the class Field, this one will multiply by distribution the Field elements mu1
, ..., mu8
, lambda1
, ..., lambda8
.
Left and Right Expansions: Remark: this method applies only on Expression class objects. The code
myExpression.leftExpansion();
myExpression.rightExpansion();
will expand the expression object with the method described in [1]. So it first checks whether the expression is of degree 3 or 4, and then applies the right method (depending on whether the expression is of degree 3 or 4 and whether the expansion is left or right).
The output is a Polynomial class object that is equal to zero on
Equations: Remark: this method applies only on Expression class objects. The code
myExpression.equations();
computes the polynomials myExpression.leftExpansion()
and myExpression.rightExpansion()
, then computes the polynomial
Usage
var X = new Monomial({ K: new Field('1'), letter: 1, ind: [], exp: []}); // initialize monomial element
var a1 = new Action(1), a2 = new Action(2), a3 = new Action(3); // initialize 3 actions elements
var exp1 = new Expression([[a1, X], a2]) // initialize an expression of degree 3
var exp2 = new Expression([[[a1, a2], a3], X]) // initialize an expression of degree 4
var p = exp1.equations() // compute the equation on K that emerges from this expression
console.log(p.read)
To obtain the wanted equations from the article [1], we first define some basic objects.
// Initialize X (a monomial in the algebra) and actions b, b* and b** ----------------------------------------------
var X = new Monomial({K: new Field('1'), letter: 1, ind: [], exp: []});
var a1 = new Action(1), a2 = new Action(2), a3 = new Action(3);
// Define the expressions we need ----------------------------------------------------------------------------------
var expressions = [
new Expression([[a2,X], a1]),
new Expression([[X,a2], a1]),
new Expression([a1, [X,a2]]),
new Expression([a1, [a2,X]]),
new Expression([[[a1,a2], a3], X]),
new Expression([[a1, [a2,a3]], X]),
new Expression([X, [a1, [a2,a3]]]),
new Expression([X, [[a1,a2], a3]])
];
Then, we compute the result with
var results = {};
expressions.forEach(d =>{
let zeroPolynomialP = d.equations(); // compute the polynomial equation P = 0 that arises from this expression
let exp = d.read(); // determine a string that represents the initial expression
results[exp] = {};
zeroPolynomialP.value.forEach((v,k) => {
results[exp][v.baseVector] = v.value.K.value; // store the equations on K that are equal to zero by taking coefficients of base vectors of P
});
});
Finally display the result with
console.log(results);
or
for(let d in results){
for(let dd in results[d]){
//console.log(results[d][dd]);
};
};