AbelianEquationsSolver::AbelianEquationsSolver( const AbelianGroup& a , const VectorOf<Word>& v , int numOfVar ) : rawA( a ), A( FPGroup() ), rawSystem( v ), system( v.length() ), b( v.length() ), x( numOfVar ), torsion( numOfVar ), params( numOfVar ), numberOfVariables( numOfVar ), sysRank( 0 ), haveSol( -1 ) { FPGroup G( a.getFPGroup() ); VectorOf<Chars> q( G.numberOfGenerators() - numberOfVariables ); for( int i = numberOfVariables ; i < G.numberOfGenerators() ; i++ ) q[ i - numberOfVariables ] = (G.namesOfGenerators())[i]; if( G.getRelators().cardinality() ) { SetOf<Word> s = G.getRelators(); SetIterator<Word> I(s); SetOf<Word> news; while( !I.done() ) { Word w = I.value(); for( int j = 0 ; j < w.length() ; j++ ) { int p = Generator( w[j] ).hash(); if( p > 0 ) w[j] = Generator( p - numberOfVariables ); else w[j] = Generator( p + numberOfVariables ); } news.adjoinElement( w ); I.next(); } FPGroup G1( q , news ); A = AbelianGroup( G1 ); } else A = AbelianGroup( FPGroup(q) ); }
int main( ) { FPGroup G; cout << "Enter nilpotentcy class first then group "; int NilpotentcyClass; cin >> NilpotentcyClass; Chars errMsg = cin >> G; if (errMsg.length()>0) return 1; NilpotentGroup ng(G.namesOfGenerators(), NilpotentcyClass,makeVectorOf(G.getRelators())); ng.initialize(); VectorOf<Word> vw; Word w; for (int i=1;true;i++){ cout << endl << "Enter the "<<i<<" generator of subgroup"<< endl; cout << "Empty word to finish: "; w = G.readWord(cin,errMsg); if (w.length()==0) break; if (errMsg.length()>0) return 1; vw.append(w); } SGOfNilpotentGroup sg(ng,vw); sg.initBasis(); sg.printBasis(cout); cout << "The Hirsch number :" << sg.theHirschNumber() << endl; cout << "Index in parent group :" << sg.index() << endl; cout << "Is Trivial :" << sg.isTrivial() << endl; cout << "Is Central :" << sg.isCentral() << endl; cout << "Is normal :" << sg.isNormal() << endl; cout << "Is abelian :" << sg.isAbelian() << endl; cout << "Subgroup class :" << sg.subgroupClass() << endl; cout << "Generators of normal closure :" << endl; vw = sg.normalClosureGens(); for (int i=0;i<vw.length();i++){ G.printWord(cout,vw[i]); cout << endl; } PresentationForSNG sgp = sg.makePresentation(); cout << "Presentation of subgroup :" << endl; sgp.print(cout); cout << endl << "Enter the word :"; errMsg = ""; w = G.readWord(cin,errMsg); if (errMsg.length()>0){ cout << errMsg; return 1; } cout << endl << "Does subgroup contain the word :" << sg.contains(w) << endl; PolyWord result; if (sg.decompose(ng.decompose(w),result)) cout << "Decomposition in sg basis :" << sg.asDecomposition(result); else cout << "Subgroup does not contain this word"; }
// can be invoced only after the cyclic decomposition has been computed bool AbelianEquationsSolver::root( Word& w , int n ) const { AbelianGroup A1 = A.getCanonicalSmithPresentation(); FPGroup G = A1.getFPGroup(); AbelianWord nw = A.oldInAbelianForm( w ); nw = A.oldToNewGens( nw ); Word ans; VectorOf<Integer> powers = nw.getPowers(); for( int i = 0 ; i < powers.length() ; i++ ) { Generator g( i + 1 ); int ord = A1.orderOfElt( g ).as_long(); int pow = powers[i].as_long(); if( pow ) if( !ord ) { if( pow % n ) return no; else for( int j = 0 ; j < abs(pow / n) ; j++ ) ans *= ( (pow / n) > 0 ) ? g : inv(g); } else if( pow % n ) { ord = ( ord > 0 ) ? ord : -ord; int x; for( x = -ord ; x < ord ; x++ ) if( ! ( (n * x - pow) % ord ) ) break; for( int j = 0 ; j < abs( x ) ; j++ ) ans *= ( x > 0 ) ? g : inv(g); } else for( int j = 0 ; j < abs(pow / n) ; j++ ) ans *= ( (pow / n) > 0 ) ? g : inv(g); } nw = AbelianWord( G.numberOfGenerators() , ans ); nw = A.newToOldGens( nw ); w = nw.getWord(); return yes; }
Subgroup& Subgroup::deleteGenerator( const Word& w ) { VectorOf<Word> theGenerators = look()->theGenerators; int i = theGenerators.indexOf(w); if ( i == -1 ) error("attempt to delete nonexistent word in Subgroup::deleteGenerator"); else { int len = theGenerators.length(); VectorOf<Word> temp(len - 1); int k = 0; for( int j = 0; j < len; ++j ) if ( j != i ) temp[k++] = theGenerators[j]; change()->theGenerators = temp; enhance()->theOrder = -1; // @stc not yet correct: the order does not necessarily become unknown return *this; } }
void AbelianSGPresentationRep::makeFile( ) { File file; VectorOf<AbelianWord> cyclicGens = newToOldGens(); int numofnewgens = cyclicGens.length(); int rank = rankOfFreeAbelianFactor(); char s[10]; Word tmpWord; file.setColor(titleColor); file << "New generators of the subgroup expressed in terms of the given generators:" << endl; file.setColor(mainColor); for( int i = 0; i < rank; ++i ) { file << "f" << i+1 << " = "; tmpWord = fromSGPGensToSGGens(cyclicGens[i].getWord()); theParent.getFPGroup().printWord(file,theParent.oldInAbelianForm(tmpWord).getWord() ); file << endl; } for( int i = rank; i < numofnewgens; ++i ) { file << "t" << i - rank + 1 << " = "; tmpWord = fromSGPGensToSGGens(cyclicGens[i].getWord()); theParent.getFPGroup().printWord(file,theParent.oldInAbelianForm(tmpWord).getWord() ); file << endl; } file << endl; file.setColor(titleColor); file << "Given generators expressed in terms of the generators for the canonical decomposition of the subgroup:" << endl; file.setColor(mainColor); for( int i = 0; i < theSGGens.length(); ++i ) { theParent.getFPGroup().printWord( file,theSGGens[i] ); file << " = "; if (fromSGGensToSGPGens(theSGGens[i],tmpWord)) printWordInNewGens(file,oldToNewGens(oldInAbelianForm(tmpWord))); file << endl; } file << end; theFileName = file.getFileName(); }
VectorOf<Word> SGOfFreeNilpotentGroupRep::normalClosureBasis() const { //@ep I have found that the process is slower with the full basis, // so I form it from the scratch. MalcevSet newBasis(theGenerators, theParentGroup.collector()); newBasis.makeNormalClosure(); // The basis is found. Now we try to reduce it to make further // processing easier. VectorOf<Word> basis = newBasis.getCommutatorWords(); // First, we reduce words in terms of basic commutators. // We could proceed without this step, but it helps // to reduce the second one greatly. FreeGroup F( theParentGroup.theHirschNumber() ); basis = F.nielsenBasis(basis); // Convert words in terms of basic commutators to group // generators. for(int i = 0; i < basis.length(); i++) { PolyWord pw = basis.val(i); basis[i] = theParentGroup.commutators().wordForm().toWord(pw); } // Now reduce this vector FreeGroup F1( theParentGroup.numberOfGenerators() ); basis = F1.nielsenBasis(basis); return basis; }
//@njz:default value removed. defined in .h file //void AbelianEquationsSolver::findSolutions( File& file , bool out = true ) void AbelianEquationsSolver::findSolutions( File& file , bool out) // { haveSol = 0; if( !A.haveCyclicDecomposition() ) A.computeCyclicDecomposition(); if( !A.havePrimaryDecomposition() ) A.findPrimaryBasis(); if( !rawA.haveCyclicDecomposition() ) rawA.computeCyclicDecomposition(); if( !rawA.havePrimaryDecomposition() ) rawA.findPrimaryBasis(); makeSystem(); if( out ) { if( system.length() > 1 ) file << "The system of equations: " << endl << endl; else file << "The equation: " << endl << endl; printRawSystem( file ); file << endl << "can be transformed to the one: " << endl << endl; printSystem( file ); if( system.length() > 1 ) file << endl << "Finding solutions of this system ..." << endl << endl; else file << endl << "Finding solutions of this equation ..." << endl << endl; } //@njz // int **matrix = new (int*)[ system.length() ]; int **matrix = new int*[ system.length() ]; // int i,j,k,i1,j1; for( i = 0 ; i < system.length() ; i++ ) { matrix[i] = new int[ numberOfVariables ]; for( j = 0 ; j < numberOfVariables ; j++ ) { Integer u = (AbelianWord( numberOfVariables , system[i] ))[j]; matrix[i][j] = u.as_long(); } } VectorOf< VectorOf<int> > transform; VectorOf<int> trans(3); // diagonalization of the matrix sysRank = 0; for( i = 0 ; ( i < numberOfVariables && i < system.length() ) ; i++ ) { bool flag = false; for( j = i ; j < system.length() ; j++ ) { for( k = i ; k < numberOfVariables ; k++ ) if( matrix[j][k] ) { flag = true; break; } if( flag ) break; } if( k == numberOfVariables && j == system.length() ) { if( sysRank ) break; int q; for( q = 0 ; q < b.length() ; q++ ) if( !A.isTrivial( Word( b[q] ) ) ) { haveSol = -1; if( out ) if( system.length() > 1 ) file << "while computing the canonical form of the system it was found that this system has no solutions." << endl; else file << "while computing the canonical form of the equation it was found that this equation has no solutions." << endl; return; } haveSol = 0; if( out ) if( system.length() > 1 ) file << "while computing the canonical form of the system it was found that this system has all group as a set of solutions." << endl; else file << "while computing the canonical form of the equation it was found that this equation has all group as a set of solutions." << endl; return; } int *tmp = matrix[i]; matrix[i] = matrix[j]; matrix[j] = tmp; Word r = b[i]; b[i] = b[j]; b[j] = r; for( j = 0 ; j < system.length() ; j++ ) { int t = matrix[j][i]; matrix[j][i] = matrix[j][k]; matrix[j][k] = t; } if( i != k ) { trans[0] = i; trans[1] = k; trans[2] = 0; transform.append( trans ); } while( true ) { bool check; bool flag; int z; bool done = false; int count = i + 1; while( !done ) { for( j = count ; j < system.length() ; j++ ) if( matrix[j][i] && abs(matrix[i][i]) != abs(matrix[j][i]) ) break; if( j == system.length() ) break; count = j + 1; flag = false; while( !flag ) { if( abs(matrix[i][i]) > abs(matrix[j][i]) ) { z = matrix[i][i] / matrix[j][i]; for( k = i ; k < numberOfVariables ; k++ ) matrix[i][k] = matrix[i][k] - matrix[j][k] * z; b[i] = b[i] * A.getFPGroup().raiseToPower(b[j],-z); } else { z = matrix[j][i] / matrix[i][i]; for( k = i ; k < numberOfVariables ; k++ ) matrix[j][k] = matrix[j][k] - matrix[i][k] * z; b[j] = b[j] * A.getFPGroup().raiseToPower(b[i],-z); } if( !matrix[i][i] || !matrix[j][i] ) { if( matrix[i][i] == 0 ) { tmp = matrix[i]; matrix[i] = matrix[j]; matrix[j] = tmp; r = b[i]; b[i] = b[j]; b[j] = r; } flag = true; } } if( count == system.length() ) done = true; } check = true; for( j = i + 1 ; j < numberOfVariables ; j++ ) if( matrix[i][j] % matrix[i][i] ) { check = false; break; } if( check ) break; done = false; count = i + 1; while( !done ) { for( j = count ; j < numberOfVariables ; j++ ) if( matrix[i][j] && abs(matrix[i][i]) != abs(matrix[i][j]) ) break; if( j == numberOfVariables ) break; count = j + 1; flag = false; while( !flag ) { if( abs(matrix[i][i]) > abs(matrix[i][j]) ) { z = matrix[i][i] / matrix[i][j]; for( k = i ; k < system.length() ; k++ ) matrix[k][i] = matrix[k][i] - matrix[k][j] * z; trans[0] = j; trans[1] = i; trans[2] = -z; transform.append( trans ); } else { z = matrix[i][j] / matrix[i][i]; for( k = i ; k < system.length() ; k++ ) matrix[k][j] = matrix[k][j] - matrix[k][i] * z; trans[0] = i; trans[1] = j; trans[2] = -z; transform.append( trans ); } if( !matrix[i][i] || !matrix[i][j] ) { if( matrix[i][i] == 0 ) { for( k = i ; k < system.length() ; k++ ) { int a = matrix[k][i]; matrix[k][i] = matrix[k][j]; matrix[k][j] = a; } if( i != j ) { trans[0] = i; trans[1] = j; trans[2] = 0; transform.append( trans ); } } flag = true; } } if( count == numberOfVariables ) done = true; } check = true; for( j = i + 1 ; j < system.length() ; j++ ) if( matrix[j][i] % matrix[i][i] ) { check = false; break; } if( check ) break; } for( j = i + 1 ; j < system.length() ; j++ ) if( matrix[j][i] ) { int z = matrix[j][i] / matrix[i][i]; for( k = i ; k < numberOfVariables ; k++ ) matrix[j][k] = matrix[j][k] - matrix[i][k] * z; b[j] = b[j] * A.getFPGroup().raiseToPower(b[i],-z); } for( j = i + 1 ; j < numberOfVariables ; j++ ) if( matrix[i][j] ) { int z = matrix[i][j] / matrix[i][i]; for( k = i ; k < system.length() ; k++ ) matrix[k][j] = matrix[k][j] - matrix[k][i] * z; trans[0] = i; trans[1] = j; trans[2] = -z; transform.append( trans ); } sysRank++; } for( i = sysRank ; i < system.length() ; i++ ) { if( !A.isTrivial( Word( b[i] ) ) ) { haveSol = -1; if( out ) if( system.length() > 1 ) file << "while computing the canonical form of the system it was found that this system has no solutions." << endl; else file << "while computing the canonical form of the equation it was found that this equation has no solutions." << endl; return; } } // finding solutions and output in file if( out ) { file << "The canonical form: "; file << endl << endl; } for( int p = 0 ; p < sysRank ; p++ ) { if( out ) { file << "x" << p + 1; if( matrix[p][p] != 1 ) file << "^" << matrix[p][p]; file << " = "; } AbelianWord w = A.oldInAbelianForm( b[p] ); w = A.oldToNewGens( w ); w = A.newToOldGens( w ); b[p] = w.getWord().freelyReduce(); if( out ) { A.getFPGroup().printWord( file , b[p] ); file << endl; } } VectorOf<int> xNums( numberOfVariables ); for( i = 0 ; i < sysRank ; i++ ) if( root( b[i] , matrix[i][i] ) ) { x[i] = b[i]; xNums[i] = i; if( !A.isFree() ) { VectorOf<int> tmp(2); tmp[0] = ( matrix[i][i] > 0 ) ? matrix[i][i] : -matrix[i][i]; tmp[1] = 1; torsion[i].append( tmp ); } } else { haveSol = -1; if( out ) { if( system.length() > 1 ) file << endl << "The system is unsolvable because there are no solutions for: " << endl << endl; else file << endl << "The equation is unsolvable because there are no solutions for: " << endl << endl; file << "x" << i + 1; if( matrix[i][i] != 1 ) file << "^" << matrix[i][i]; file << " = "; A.getFPGroup().printWord( file , b[i].freelyReduce() ); } return; } for( j = sysRank ; j < numberOfVariables ; j++ ) { x[j] = Word(); xNums[j] = j; VectorOf<int> tmp(2); tmp[0] = j - sysRank + 1; tmp[1] = 1; params[j].append( tmp ); } for( i = transform.length() - 1 ; i >= 0 ; i-- ) { trans = transform[i]; if( !trans[2] ) { int ind1 = xNums.indexOf( trans[0] ); int ind2 = xNums.indexOf( trans[1] ); xNums[ind1] = trans[1]; xNums[ind2] = trans[0]; } else { int ind1 = xNums.indexOf( trans[0] ); int ind2 = xNums.indexOf( trans[1] ); x[ind1] *= A.getFPGroup().raiseToPower( x[ind2] , trans[2] ); int len = torsion[ind1].length(); for( j = 0 ; j < torsion[ind2].length() ; j++ ) { bool f = false; for( k = 0 ; k < len ; k++ ) if( torsion[ind1][k][0] == torsion[ind2][j][0] ) { f = true; break; } if( f ) torsion[ind1][k][1] += torsion[ind2][j][1] * trans[2]; else { VectorOf<int> tmp = torsion[ind2][j]; tmp[1] *= trans[2]; torsion[ind1].append( tmp ); } } len = params[ind1].length(); for( j = 0 ; j < params[ind2].length() ; j++ ) { bool f = false; for( k = 0 ; k < len ; k++ ) if( params[ind1][k][0] == params[ind2][j][0] ) { f = true; break; } if( f ) params[ind1][k][1] += params[ind2][j][1] * trans[2]; else { VectorOf<int> tmp = params[ind2][j]; tmp[1] *= trans[2]; params[ind1].append( tmp ); } } } } for( i = 0 ; i < x.length() ; i++ ) { AbelianWord w = A.oldInAbelianForm( x[i] ); w = A.oldToNewGens( w ); w = A.newToOldGens( w ); x[i] = w.getWord(); } // output in file if( out ) { file << endl << "The set of solutions can be presented as follows: " << endl << endl; FPGroup G = rawA.getFPGroup(); FPGroup G1 = A.getFPGroup(); for( i = 0 ; i < numberOfVariables ; i++ ) { int n = xNums.indexOf( i ); bool flag = false; G.printWord( file , Generator( i + 1 ) ); file << " -> "; if( x[n].length() ) { G1.printWord( file , x[n].freelyReduce() ); flag = true; } for( j = 0 ; j < torsion[n].length() ; j++ ) { VectorOf<int> tmp = torsion[n][j]; int z = tmp[1] % tmp[0]; if( z ) if( tmp[1] > 0 ) { if( flag ) file << " + "; if( tmp[1] != 1 ) file << tmp[1] << " p( " << tmp[0] << " )"; else file << "p( " << tmp[0] << " )"; flag = true; } else { file << " - "; if( tmp[1] != -1 ) file << -tmp[1] << " p( " << tmp[0] << " )"; else file << "p( " << tmp[0] << " )"; flag = true; } } for( j = 0 ; j < params[n].length() ; j++ ) { VectorOf<int> tmp = params[n][j]; if( tmp[1] ) if( tmp[1] > 0 ) { if( flag ) file << " + "; if( tmp[1] != 1 ) file << tmp[1] << " t" << tmp[0]; else file << "t" << tmp[0]; flag = true; } else { file << " - "; if( tmp[1] != -1 ) file << -tmp[1] << " t" << tmp[0]; else file << "t" << tmp[0]; flag = true; } } if( !flag ) file << "1 "; if( i != numberOfVariables ) file << ","; file << endl; } file << endl << "where p( n ) is any element of n-heigth and t_i - any element of the group." << endl; } VectorOf< VectorOf< VectorOf<int> > > t( numberOfVariables ); VectorOf< VectorOf< VectorOf<int> > > p( numberOfVariables ); VectorOf<Word> x1( numberOfVariables ); for( i = 0 ; i < numberOfVariables ; i++ ) { int n = xNums.indexOf( i ); x1[i] = x[n]; t[i] = torsion[n]; p[i] = params[n]; } torsion = t; params = p; x = x1; for( i = 0 ; i < system.length() ; i++ ) delete [] matrix[i]; delete [] matrix; }
int main ( ) { Chars errMsg; GHNConfig c; //cout << c << endl; ifstream in("../wp.in"); in >> c; cout << c << endl; int numOfVars; cout << "Enter the number of variables: "; cin >> numOfVars; cout << endl; FreeGroup G; cout << "Enter a free group: "; errMsg = cin >> G; if( errMsg.length() > 0 ) { cout << errMsg; exit(0); } cout << endl; VectorOf<Chars> v = G.namesOfGenerators(); int numOfConst = v.length(); int rLen = v.length() + numOfVars; VectorOf<Chars> r(rLen); int j; for( j = 0; j < v.length(); ++j ) if( v[j][0] != 'x' && v[j][0] != 'X' ) r[j] = v[j]; else error("x is reserved for variables\n"); char s[3] = {0,0,0}; s[0] = 'x'; for( int i = j; i < rLen; ++i ) { s[1] = i-j+1+48; r[i] = s; } FreeGroup F(r); cout << "Enter an equation (a word) with variables x1 ... x" << numOfVars << ": "; Word w; w = F.readWord(cin,errMsg); if( errMsg.length() > 0 ) { cout << errMsg; exit(0); } cout << endl; VectorOf<Word> im(rLen); for( int i = 0; i < rLen; ++i ) im[i] = Word(Generator(i+1)); Map M(F,F,im); int popSize = c.populationSize(); GAWord pop[numOfVars][popSize],newPop[numOfVars][popSize]; for( int k = 0; k < numOfVars; ++k ) for( int i = 0; i < popSize; ++i ) { pop[k][i] = GAWord(numOfConst,Word()); } int fit[popSize]; // the main loop int numOfGens = c.numOfGenerations(); //bool bHaveFitnessScaling = c.haveFitnessScaling(); float crossRate = c.chanceOfCrossover(); float mutRate = c.chanceOfMutation(); UniformRandom devgen; int max, min, minInd, g; // create the original random populations for( int k = 0; k < numOfVars; ++k ) for( int i = 0; i < popSize; ++i ) { pop[k][i] = pop[k][i].randomWord(); } for( g = 0; g < numOfGens || numOfGens == -1; ++g ) { min = MAXINT; max = 0; minInd = -1; // compute fitness values for( int i = 0; i < popSize; ++i ) { for( int k = 0; k < numOfVars; ++k ) M.setGeneratingImages(numOfConst+k,(pop[k][i]).getWord()); fit[i] = M.imageOf(w).freelyReduce().length(); if( fit[i] < min ) { min = fit[i]; minInd = i; } else if( fit[i] > max ) max = fit[i]; } // print current results cout << "Generation: " << g << " Fitness: " << min << endl; /* if( g % 100 == 0 ) { for( int i = 0; i < popSize; ++i ) { cout << "x" << i << " = "; F.printWord(cout, (pop[i]).getWord()); cout << endl; } cout << endl; } */ // exit if found a solution if( min == 0 ) { for( int k = 0; k < numOfVars; ++k ) { cout << "x" << k+1 << " = "; F.printWord(cout, (pop[k][minInd]).getWord()); cout << endl; } return 0; } // make fitness values suitable for Roulette wheel selection int base = max + 1; for( int i = 0; i < popSize; ++i ) fit[i] = base - fit[i]; // fitness scaling if( c.haveFitnessScaling() ) for( int i = 0; i < popSize; ++i ) fit[i] = fit[i] * fit[i]; // crossover RouletteWheel<int> wheel(popSize,fit); for( int k = 0; k < numOfVars; ++k ) for( int i = 0; i < popSize; ++i ) { if( devgen.rand() <= crossRate ) { int i1 = wheel.GetIndex(); int i2 = wheel.GetIndex(); newPop[k][i] = pop[k][i1].crossover(pop[k][i2]); } else { newPop[k][i] = pop[k][i]; } } // mutation for( int k = 0; k < numOfVars; ++k ) for( int i = 0; i < popSize; ++i ) { if( devgen.rand() <= mutRate ) { newPop[k][i] = newPop[k][i].mutate(); } } // elitist selection for( int k = 0; k < numOfVars; ++k ) if( c.haveElitistSelection() ) { newPop[k][0] = pop[k][minInd]; } // prepare for the next iteration for( int k = 0; k < numOfVars; ++k ) for( int i = 0; i < popSize; ++i ) { pop[k][i] = newPop[k][i]; } } }
// put the words to the set MalcevSet::MalcevSet(const VectorOf<Word>& v, const NGCollector& nc) : isBasis(false), isNormal(dontknow), theCollector(nc) { for(int i = 0; i < v.length(); i++) addWord( v.val(i) ); }