001/*
002 * $Id$
003 */
004
005package edu.jas.structure;
006
007
008
009/**
010 * Monoid element interface. Defines the multiplicative methods.
011 * @param <C> element type
012 * @author Heinz Kredel
013 */
014
015public interface MonoidElem<C extends MonoidElem<C>> extends Element<C> {
016
017
018    /**
019     * Test if this is one.
020     * @return true if this is 1, else false.
021     */
022    public boolean isONE();
023
024
025    /**
026     * Test if this is a unit. I.e. there exists x with this.multiply(x).isONE()
027     * == true.
028     * @return true if this is a unit, else false.
029     */
030    public boolean isUnit();
031
032
033    /**
034     * Multiply this with S.
035     * @param S
036     * @return this * S.
037     */
038    public C multiply(C S);
039
040
041    /**
042     * Divide this by S.
043     * @param S
044     * @return this / S.
045     */
046    public C divide(C S);
047
048
049    /**
050     * Remainder after division of this by S.
051     * @param S
052     * @return this - (this / S) * S.
053     */
054    public C remainder(C S);
055
056
057    /**
058     * Quotient and remainder by division of this by S.
059     * @param S
060     * @return [this/S, this - (this/S)*S].
061     */
062    @SuppressWarnings("unchecked")
063    default public C[] quotientRemainder(C S) {
064        return (C[]) new MonoidElem[] { divide(S), remainder(S) }; 
065    }
066
067
068    /**
069     * Right division.
070     * Returns commutative divide if not overwritten.
071     * @param a element.
072     * @return right, with a * right = this
073     */
074    default public C rightDivide(C a) {
075        if (((MonoidFactory<C>)factory()).isCommutative()) {
076           return divide(a);
077        }
078        throw new UnsupportedOperationException("operation not implemented");
079    }
080
081
082    /**
083     * Left division.
084     * Returns commutative divide if not overwritten.
085     * @param a element.
086     * @return left, with left * a = this
087     */
088    default public C leftDivide(C a) {
089        if (((MonoidFactory<C>)factory()).isCommutative()) {
090           return divide(a);
091        }
092        throw new UnsupportedOperationException("operation not implemented");
093    }
094
095
096    /**
097     * Right remainder.
098     * Returns commutative remainder if not overwritten.
099     * @param a element.
100     * @return r = this - a * (1/right), where a * right = this.
101     */
102    default public C rightRemainder(C a) {
103        if (((MonoidFactory<C>)factory()).isCommutative()) {
104           return remainder(a);
105        }
106        throw new UnsupportedOperationException("operation not implemented");
107    }
108
109
110    /**
111     * Left remainder.
112     * Returns commutative remainder if not overwritten.
113     * @param a element.
114     * @return r = this - (1/left) * a, where left * a = this.
115     */
116    default public C leftRemainder(C a) {
117        if (((MonoidFactory<C>)factory()).isCommutative()) {
118           return remainder(a);
119        }
120        throw new UnsupportedOperationException("operation not implemented");
121    }
122
123
124    /**
125     * Two-sided division.
126     * Returns commutative divide if not overwritten.
127     * @param a element.
128     * @return [left,right], with left * a * right = this
129     */
130    @SuppressWarnings("unchecked")
131    default public C[] twosidedDivide(C a) {
132        if (((MonoidFactory<C>)factory()).isCommutative()) {
133           C[] ret = (C[]) new MonoidElem[2];
134           ret[0] = divide(a);
135           ret[1] = ((MonoidFactory<C>)factory()).getONE();
136           return ret;
137        }
138        throw new UnsupportedOperationException("operation not implemented");
139    }
140
141
142    /**
143     * Two-sided remainder.
144     * Returns commutative remainder if not overwritten.
145     * @param a element.
146     * @return r = this - (a/left) * a * (a/right), where left * a * right = this.
147     */
148    default public C twosidedRemainder(C a){
149        if (((MonoidFactory<C>)factory()).isCommutative()) {
150           return remainder(a);
151        }
152        throw new UnsupportedOperationException("operation not implemented");
153    }
154
155
156    /**
157     * Inverse of this. Some implementing classes will throw
158     * NotInvertibleException if the element is not invertible.
159     * @return x with this * x = 1, if it exists.
160     */
161    public C inverse(); /*throws NotInvertibleException*/
162
163
164    /**
165     * Power of this to the n-th.
166     * @param n integer exponent.
167     * @return a**n, with a**0 = 1 and a**{-n} = {1/a}**n.
168     * Java 8 only
169     */ 
170    @SuppressWarnings("unchecked")
171    default public C power(long n) {
172        //System.out.println("this = " + this + ", n = " + n);
173        return Power.<C>power((MonoidFactory<C>)factory(), (C)this, n);
174    }
175
176}