// adds w to the set // returns true iff the set was changed bool MalcevSet::addWord( const PolyWord& pw ) { bool wasChanged = false; PolyWord remainder = collect(pw); while( ! remainder.isEmpty() ) { Generator key = leader(remainder); // if there is no word with the same leader, include the remainder to the set if( ! theSet.bound(key) ) { theSet.bind( key, remainder ); isBasis = false; isNormal = dontknow; return true; } // reduce the remainder PolyWord currentWord = theSet.valueOf(key); if( reduceWords( currentWord, remainder) ) { theSet.bind( key, currentWord ); isBasis = false; isNormal = dontknow; wasChanged = true; } } return wasChanged; }
bool MalcevSet::isNormalClosure() const { if( isNormal != dontknow ) return isNormal; if( ! isBasis ) error("Attempt to use MalcevSet::isNormalClosure before the set is full."); const BasicCommutators& BC = theCollector.commutators(); MalcevSet* This = (MalcevSet *)this; // to break physical constness //the subgroup is normal iff any w^x is in the set for(int i = 1; i < BC.theFirstOfWeight(BC.nilpotencyClass() ); i++) { if( ! theSet.bound( Generator(i) ) ) continue; PolyWord W = theSet.valueOf( Generator(i) ); for(int j = 1; j <= BC.numberOfGenerators(); j++) { PolyWord conj = collect( Letter(j, -1) * W * Letter(j, 1) ); checkMembership(conj); if(! conj.isEmpty() ) { This->isNormal = no; return false; } } } This->isNormal = yes; return true; }
void MalcevSet::checkMembership(PolyWord& remainder) const { while( ! remainder.isEmpty() && theSet.bound( leader(remainder) ) ) { PolyWord curWord = theSet.valueOf( leader(remainder) ); if( absPower(remainder) % absPower(curWord) != 0 ) break; // The rest can be reduced. Do it. reduceWords( curWord, remainder ); } }
bool MalcevSet::reduceWords(PolyWord& pw1, PolyWord& pw2) const { if(pw1.isEmpty() || pw2.isEmpty()) error("MalcevSet::reduceWords: empty argument"); bool firstChanged = false; int power1 = absPower(pw1); int power2 = absPower(pw2); // make both PolyWords to be of distinct signs if( sign(pw1) ^ sign(pw2) == 0) // if they have the same sign pw2 = pw2.inverse(); // in fact, this is Euclid algorithm for finding GCD do { if( power1 > power2 ) { // swapping two words PolyWord tmp = pw1; pw1 = pw2; pw2 = tmp; int t = power1; power1 = power2; power2 = t; firstChanged = true; } power2 -= power1; pw2 = theCollector.multiply(pw1, pw2); } while(power2 != 0); return firstChanged; }
bool MalcevSet::decomposeWord(const PolyWord& w, PolyWord& decomp) const { if( ! isBasis ) error("Attempt to use MalcevSet::decomposeWord before the set is full."); PolyWord remainder = theCollector.collect(w); decomp = PolyWord(); // try to decompose the remainder while( ! remainder.isEmpty() && theSet.bound( leader(remainder) ) ) { PolyWord divisor = theSet.valueOf( leader(remainder) ); if( absPower(remainder) % absPower(divisor) != 0 ) break; // The remainder can be reduced. Do it. int divPower = power(remainder) / power(divisor); decomp.append( Letter( leader(remainder), divPower ) ); if( divPower < 0 ) { divPower = - divPower; } else { divisor = theCollector.inverse(divisor); } for(int i = 0; i < divPower; i++) { remainder = theCollector.multiply(divisor, remainder); } } // if the remainder cannot be decomposed if( ! remainder.isEmpty() ) { decomp = PolyWord(); return false; } // if the remainder initially was empty if( decomp.isEmpty() ) return true; // initially decomp is a series of letters (gen, power), // where gen is a leader of decomposition component and // power is its power // now translate decomp to Malcev basis terms: replace // gen with index of basis word having leader gen int curElement = 0; // index of current basis element PolyWordIterator iter(decomp); iter.startFromLeft(); for( int c = 1; c <= theCollector.commutators().theHirschNumber(); c++ ) { Generator theLeader(c); if( ! theSet.bound(theLeader) ) continue; ++curElement; if( iter.thisLetter().gen == theLeader ) { iter.thisLetter().gen = Generator(curElement); iter.stepRight(); if( iter.done() ) break; } } return true; }
bool MalcevSet::contains(const Word& w) const { PolyWord pw = theCollector.collect(w); checkMembership(pw); return pw.isEmpty(); }