GroupJep - Exact arithmetic over the integers, rationals and other groups


The org.lsmp.djep.groupJep package offers:

This package is primarily a bit of a play thing, allowing the JEP parser and evaluator to be used with arbitrary groups. It should not be treated as a substitute for a dedicated computer algebra package but it does allow a bit of experimentation with different groups rings and fields.

An interactive console applet interactive console applet illustrates the functionality of GroupJep.

Basic usage

The GroupJep package is relatively easy to use, all the standard JEP features are enabled. To create a version of JEP for a particular group the GroupJep(GroupI group) constructor should be called where the argument is the specification of a certain group. For example to work of arbitrary precision integers to calculate factorial 20 use:
import org.lsmp.djep.groupJep.*;
import org.lsmp.djep.groupJep.groups.*;

JEP j = new GroupJep(new Integers());
Node node = j.parse("1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20");
Object value = j.evaluate(node);
System.out.println(value.toString());
// prints 2432902008176640000
A number of predefined groups are provided. These are all found in the org.lsmp.djep.groupJep.groups package. Examples of the use of these groups:
import org.lsmp.djep.groupJep.*;
import org.lsmp.djep.groupJep.groups.*;

class GroupExamples {
public static void main(String args[])
{
JEP j = new GroupJep(new Integers());
Node node = j.parse("1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20");
Object value = j.evaluate(node);
System.out.println(value.toString());
// prints 2432902008176640000

j = new GroupJep(new Rationals());
node = j.parse("(1/2)-(1/3)");
value = j.evaluate(node);
System.out.println(value.toString());
// prints 1/6

j = new GroupJep(new Zn(BigInteger.valueOf(5)));
node = j.parse("3+3");
value = j.evaluate(node);
System.out.println(value.toString()); // prints 1

node = j.parse("3*3");
value = j.evaluate(node);
System.out.println(value.toString()); // prints 4

Free groups/Polynomials

Any ring can be extended to form a FreeGroup with a single generator. In effect this allows JEP to function with polynomials as a basic type and they will always be reduced to their basic type.

To use:

import org.lsmp.djep.groupJep.interfaces.*;
import org.lsmp.djep.groupJep.*;
...
RingI ring = new Integers();
RingI freeGroup = new FreeGroup(ring,"t");
JEP j = new GroupJep(freeGroup);
// this line is needed to ensure the parser recognises the symbol t
j.addStandardConstants();

Node node = j.parse("(t + 2)*(t+4)");
Object value = j.evaluate(node);
System.out.println(value.toString()); // prints t^2+5 t+6
Note that the addStandardConstants method of JEP must be called to ensure that the variable t is added to the parser. Free groups with more than one generator can be constructed by repeatedly extending a ring:
RingI freeGroup = new FreeGroup(new FreeGroup(new Integers(),"t"),"s");

Polynomials in multiple variables can be defined by repeatidly extending.

RingI ring = new Reals();
FreeGroup fg = new ExtendedFreeGroup(ring,"x");
FreeGroup fg2 = new ExtendedFreeGroup(fg,"y");
j = new GroupJep(fg2);
j.addStandardConstants();
j.setAllowAssignment(true);
j.setAllowUndeclared(true);
Node n2 = j.parse("(x+1)*(y-2)");	
FreeGroupElement fge = (FreeGroupElement) j.evaluate(n2);
The coefficients of the polynomial can be found using:
Number co1[] = fge.getCoeffs();
for(int i=0;i<co1.length;++i)
{
	FreeGroupElement fge3 = (FreeGroupElement) co1[i];
	Number co2[] = fge3.getCoeffs();
	for(int j=0;j<co2.length;++j)
		System.out.print(co2[j]+"\t");
	System.out.println();
}
To calculate
fg.setRootVal(new Complex(5.0));
fg2.setRootVal(new Complex(4.0));
System.out.println(fge2.toString());
Complex val = fge2.getComplexValue();		

Algebraic Numbers

In a similar fashion a ring can be extended by an algebraic number t to form an AlgebraicExtension. The algebraic number is defined to be a root of a Polynomial equation with coefficients in the base ring.
import org.lsmp.djep.groupJep.*;
import org.lsmp.djep.groupJep.interfaces.*;
import org.lsmp.djep.groupJep.groups.*;
import org.lsmp.djep.groupJep.values.*;
...
RingI ring = new Integers();
// specify the polynomial 1 x^2 + 0 x -2
Number coeffs[] = new Number[]{
BigInteger.valueOf(-2),
BigInteger.ZERO,
BigInteger.ONE};
Polynomial p1 = new Polynomial(ring,"rt2",coeffs);

j = new GroupJep(new AlgebraicExtension(ring, p1));
j.addStandardConstants();

Node node = j.parse("(t+1)*(t+1)");
Object value = j.evaluate(node);
System.out.println(value.toString()); // prints 2 t+3
System.out.println(((HasComplexValueI) value).getComplexValue());
// prints (5.82842712474619, 0.0)
Note in the last line the values can be converted to approximate complex numbers (in the group constructor if the polynomial is quadratic or an n-th root then an approximation to the complex value of a solution is calculate. The value returned by j.evaluate will be an object of type AlgebraicExtensionElement which implements org.lsmp.djep.groupJep.values.HasComplexValueI by providing a getComplexValue() method. This method will use the approximate value of the root to calculate the complex value of this element.

Creating your own groups

Creating a group class is fairly straight forward. The class must implement org.lsmp.djep.groupJep.GroupI or one of the other interfaces in the org.lsmp.djep.groupJep.interfaces package which give extra properties such as RingI, FieldI. Typically the group will subclass org.lsmp.djep.groupJep.groups.Group which provides a few default methods. All groups should provide the methods:
public Number getZERO();
public Number getInverse(Number num);
public Number add(Number a,Number b);
public Number sub(Number a,Number b);
public boolean equals(Number a,Number b);
public Number valueOf(String s);

The different interfaces available and the methods they define are:

Interface Methods
GroupI public Number getZERO();
public Number getInverse(Number num);
public Number add(Number a,Number b);
public Number sub(Number a,Number b);
public boolean equals(Number a,Number b);
public Number valueOf(String s);
AbelianGroupI Same methods as GroupI.
implies group is commutative under +.
RingI Methods for GroupI plus:-
public Number getONE();
public Number mul(Number a,Number b);
public Number getMulInverse(Number num);
IntegralDomainI Same methods as RingI. This interface implies the group has: an identity for multiplication *; it is commutative under * and that cancellation is meaningful (if a is not 0 then a*b = a*c implies b = c).
HasDivI Group has some notion of division i.e. integers
public Number div(Number a,Number b);
FieldI Same methods as for RingI plus
public Number div(Number a,Number b);
HasModI The modulus function is defined:
public Number mod(Number a,Number b);
HasPowerI The power function is defined:
public Number pow(Number a,Number b);
OrderedSetI There is a natural ordering to the set so <, <=, >, >= are meaningful.
public int compare(Number a,Number b);
will return -1 if a<b, 0 if a=b, +1 if a>b.
HasListI List operations i.e. [a,b,c] is meaningful. public Number list(Number eles[]);