/*
* $Id$
*/
package edu.jas.poly;
import java.util.SortedMap;
import java.util.TreeMap;
import edu.jas.structure.MonoidElem;
import edu.jas.structure.MonoidFactory;
import edu.jas.structure.NotInvertibleException;
/**
* Word implements strings of letters for polynomials.
* @author Heinz Kredel
*/
public final class Word implements MonoidElem {
/**
* Defining alphabet in WordFactory.
*/
public final WordFactory mono;
/**
* The data structure is a String of characters.
*/
/*package*/final String val;
/**
* Stored hash code.
*/
protected int hash = 0;
/**
* Constructor for Word.
* @param m factory for words.
*/
public Word(WordFactory m) {
this(m, "");
}
/**
* Constructor for Word.
* @param m factory for words.
* @param s String
*/
public Word(WordFactory m, String s) {
this(m, s, true);
}
/**
* Constructor for Word.
* @param m factory for words.
* @param s String
* @param translate indicator if s needs translation
*/
public Word(WordFactory m, String s, boolean translate) {
mono = m;
hash = 0;
if (s == null) {
throw new IllegalArgumentException("null string not allowed");
}
if (translate) {
if (mono.translation != null) {
//System.out.println("s = " + s);
String[] S = GenPolynomialTokenizer.variableList(s);
//System.out.println("S = " + Arrays.toString(S));
val = mono.translate(S);
//System.out.println("val = " + val);
} else {
val = WordFactory.cleanSpace(s); //??
}
} else {
val = s;
}
}
/**
* Get the corresponding element factory.
* @return factory for this Element.
* @see edu.jas.structure.Element#factory()
*/
public MonoidFactory factory() {
return mono;
}
/**
* Copy this.
* @return copy of this.
*/
@Override
public Word copy() {
return new Word(mono, val, false);
}
/**
* Get the word String.
* @return val.
*/
/*package*/String getVal() {
return val;
}
/**
* Get the letter at position i.
* @param i position.
* @return val[i].
*/
public char getVal(int i) {
return val.charAt(i);
}
/**
* Get the length of this word.
* @return val.length.
*/
public int length() {
return val.length();
}
/**
* Get the string representation.
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if (val.length() == 0) {
return "";
}
StringBuffer s = new StringBuffer("\"");
String vv;
if (mono.translation == null) {
for (int i = 0; i < length(); i++) {
if (i != 0) {
s.append(" ");
}
s.append(getVal(i));
}
} else {
for (int i = 0; i < length(); i++) {
if (i != 0) {
s.append(" ");
}
s.append(mono.transVar(getVal(i)));
}
}
s.append("\"");
return s.toString();
}
/**
* Get a scripting compatible string representation.
* @return script compatible representation for this Element.
* @see edu.jas.structure.Element#toScript()
*/
@Override
public String toScript() {
if (val.length() == 0) {
return "";
}
StringBuffer s = new StringBuffer("");
if (mono.translation == null) {
for (int i = 0; i < length(); i++) {
if (i != 0) {
s.append("*"); // checked for python vs ruby
}
s.append(getVal(i));
}
} else {
for (int i = 0; i < length(); i++) {
if (i != 0) {
s.append("*"); // checked for python vs ruby
}
s.append(mono.transVar(getVal(i)));
}
}
s.append("");
return s.toString();
}
/**
* Get a scripting compatible string representation of the factory.
* @return script compatible representation for this ElemFactory.
* @see edu.jas.structure.Element#toScriptFactory()
*/
@Override
public String toScriptFactory() {
// Python case
return mono.toString();
}
/**
* Comparison with any other object.
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object B) {
if (!(B instanceof Word)) {
return false;
}
Word b = (Word) B;
// mono == b.mono ??
int t = this.compareTo(b);
//System.out.println("equals: this = " + this + " B = " + B + " t = " + t);
return (0 == t);
}
/**
* hashCode.
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
if (hash == 0) {
hash = val.hashCode();
}
return hash;
}
/**
* Is Word one.
* @return If this is the empty word then true is returned, else false.
*/
public boolean isONE() {
return (0 == this.length());
}
/**
* Is Word unit.
* @return If this is a unit then true is returned, else false.
*/
public boolean isUnit() {
return isONE();
}
/**
* Word multiplication.
* @param V other word.
* @return this * V.
*/
public Word multiply(Word V) {
return new Word(mono, this.val + V.val, false);
}
/**
* Word divide.
* @param V other word.
* @return this / V.
*/
public Word divide(Word V) {
Word[] ret = divideWord(V);
// TODO: fail if both non zero?
if (!ret[0].isONE() && !ret[1].isONE()) {
throw new IllegalArgumentException("not simple dividable: left = " + ret[0] + ", right = "
+ ret[1] + ", use divideWord");
}
return ret[0].multiply(ret[1]);
}
/**
* Word divide with prefix and suffix.
* @param V other word.
* @return [prefix(this/V), suffix(this/V)] = [left,right] with left * V *
* right = this.
*/
public Word[] divideWord(Word V) {
int i = this.val.indexOf(V.val);
if (i < 0) {
throw new NotInvertibleException("not dividable: " + this + ", other " + V);
}
int len = V.val.length();
String pre = this.val.substring(0, i);
String suf = this.val.substring(i + len);
Word[] ret = new Word[2];
ret[0] = new Word(mono, pre, false);
ret[1] = new Word(mono, suf, false);
return ret;
}
/**
* Word remainder.
* @param V other word.
* @return this (this/V). Note: not useful.
*/
public Word remainder(Word V) {
int i = this.val.indexOf(V.val);
if (i < 0) {
throw new NotInvertibleException("not dividable: " + this + ", other " + V);
}
return V;
}
/**
* Quotient and remainder by division of this by S.
* @param S a Word
* @return [this/S, this - (this/S)*S]. Note: not useful.
*/
public Word[] quotientRemainder(Word S) {
return new Word[] { divide(S), remainder(S) };
}
/**
* Word inverse.
* @return 1 / this.
*/
public Word inverse() {
if (val.length() == 0) {
return this;
}
throw new NotInvertibleException("not inversible " + this);
}
/**
* Word signum.
* @return 0 if this is one, 1 if it is non empty.
*/
public int signum() {
int i = val.length();
if (i > 0) {
i = 1;
}
assert i >= 0;
return i;
}
/**
* Word degree.
* @return total degree of all letters.
*/
public long degree() {
return val.length();
}
/**
* Word dependency on letters.
* @return sorted map of letters and the number of its occurences.
*/
public SortedMap dependencyOnVariables() {
SortedMap map = new TreeMap();
for (int i = 0; i < val.length(); i++) {
String s = String.valueOf(val.charAt(i));
Integer n = map.get(s);
if (n == null) {
n = 0;
}
n = n + 1;
map.put(s, n);
}
return map;
}
/**
* Word multiple test.
* @param V other word.
* @return true if this is a multiple of V, else false.
*/
public boolean multipleOf(Word V) {
return this.val.contains(V.val);
}
/**
* Word divides test.
* @param V other word.
* @return true if this divides V, else false.
*/
public boolean divides(Word V) {
return V.val.contains(this.val);
}
/**
* Word compareTo. Uses
*
*
* String.compareTo
*
*
* .
* @param V other word.
* @return 0 if U == V, -1 if U < V, 1 if U > V.
*/
@Override
public int compareTo(Word V) {
return this.val.compareTo(V.val);
}
/**
* Word graded comparison. Compares first be degree, then lexicographical.
* @param V other word.
* @return 0 if U == V, -1 if U < V, 1 if U > V.
*/
public int gradCompareTo(Word V) {
long e = this.degree();
long f = V.degree();
if (e < f) {
return 1;
} else if (e > f) {
return -1;
}
return this.compareTo(V);
}
/**
* Word graded comparison. Compares first be degree, then inverse
* lexicographical.
* @param V other word.
* @return 0 if U == V, -1 if U < V, 1 if U > V.
*/
public int gradInvlexCompareTo(Word V) {
long e = this.degree();
long f = V.degree();
if (e < f) {
return 1;
} else if (e > f) {
return -1;
}
return -this.compareTo(V);
}
/**
* Is word overlap.
* @param ol = [l1,r1,l2,r2] an Overlap container of four words
* @param V word
* @return true if l1 * this * r1 = l2 * V * r2, else false.
*/
public boolean isOverlap(Overlap ol, Word V) {
return ol.isOverlap(this, V);
}
/**
* Word overlap list.
* @param V other word.
* @return list of overlaps [l1,r1,l2,r2] with l1 * this * r1 = l2 * V * r2.
* If no such overlaps exist the empty overlap list is returned.
*/
public OverlapList overlap(Word V) {
OverlapList ret = new OverlapList();
Word wone = mono.getONE();
String a = this.val;
String b = V.val;
int ai = a.length();
int bi = b.length();
int j = b.indexOf(a);
if (j >= 0) {
while (j >= 0) {
String pre = b.substring(0, j);
String suf = b.substring(j + ai);
Word wpre = new Word(mono, pre, false);
Word wsuf = new Word(mono, suf, false);
ret.add(new Overlap(wpre, wsuf, wone, wone));
j = b.indexOf(a, j + ai); // +1 also inner overlaps ?
}
return ret;
}
j = a.indexOf(b);
if (j >= 0) {
while (j >= 0) {
String pre = a.substring(0, j);
String suf = a.substring(j + bi);
Word wpre = new Word(mono, pre, false);
Word wsuf = new Word(mono, suf, false);
ret.add(new Overlap(wone, wone, wpre, wsuf));
j = a.indexOf(b, j + bi); // +1 also inner overlaps ?
}
return ret;
}
if (ai >= bi) {
for (int i = 0; i < bi; i++) {
String as = a.substring(0, i + 1);
String bs = b.substring(bi - i - 1, bi);
//System.out.println("i = " + i + ", bs = " + bs + ", as = " + as);
if (as.equals(bs)) {
Word w1 = new Word(mono, b.substring(0, bi - i - 1), false);
Word w2 = new Word(mono, a.substring(i + 1), false);
ret.add(new Overlap(w1, wone, wone, w2));
break;
}
}
for (int i = 0; i < bi; i++) {
String as = a.substring(ai - i - 1, ai);
String bs = b.substring(0, i + 1);
//System.out.println("i = " + i + ", bs = " + bs + ", as = " + as);
if (as.equals(bs)) {
Word w1 = new Word(mono, b.substring(i + 1), false);
Word w2 = new Word(mono, a.substring(0, ai - i - 1), false);
ret.add(new Overlap(wone, w1, w2, wone));
break;
}
}
} else { // ai < bi
for (int i = 0; i < ai; i++) {
String as = a.substring(ai - i - 1, ai);
String bs = b.substring(0, i + 1);
//System.out.println("i = " + i + ", bs = " + bs + ", as = " + as);
if (as.equals(bs)) {
Word w1 = new Word(mono, b.substring(i + 1), false);
Word w2 = new Word(mono, a.substring(0, ai - i - 1), false);
ret.add(new Overlap(wone, w1, w2, wone));
break;
}
}
for (int i = 0; i < ai; i++) {
String as = a.substring(0, i + 1);
String bs = b.substring(bi - i - 1, bi);
//System.out.println("i = " + i + ", bs = " + bs + ", as = " + as);
if (as.equals(bs)) {
Word w1 = new Word(mono, b.substring(0, bi - i - 1), false);
Word w2 = new Word(mono, a.substring(i + 1), false);
ret.add(new Overlap(w1, wone, wone, w2));
break;
}
}
}
return ret;
}
/**
* Word pseudo least common multiple.
* @param V other word.
* @return w = l1*this*r1, with l1*this*r1 == l2*V*r2, if l1, r1, l2, r2
* exist, else null is returned.
*/
public Word lcm(Word V) {
OverlapList oll = overlap(V);
if (oll.ols.isEmpty()) {
return null;
}
Overlap ol = oll.ols.get(0);
Word g = ol.l1.multiply(this).multiply(ol.r1);
return g;
}
}
Ads help maintain this website.