/** * Takes a word and translates it into the internally used form, an array of integers. * * @param word the input word. * @return the translated word. */ private int[] translateWord(FreeWord word) { final int res[] = new int[word.size()]; for (int i = 0; i < word.size(); ++i) { final FreeWord g = word.subword(i, i + 1); final Integer idx = (Integer) this.gen2idx.get(g); res[i] = idx.intValue(); } return res; }
public Object apply(final Object x, final FreeWord w) { if (!(x instanceof Coset)) { return null; } final Coset coset = (Coset) x; if (coset.getAction() != this) { return null; } int current = coset.getIndex(); if (current < 1 || current > size()) { return null; } for (int i = 0; i < w.length(); ++i) { final Integer j = (Integer) this.gen2idx.get(w.subword(i, i + 1)); if (j == null) { return null; } else { final int row[] = (int[]) this.table.get(current); current = row[j.intValue()]; } } return new Coset(current); }
/** * Constructs a CosetTable instance with a limit on the number of table rows that may be present * at any stage of the construction process. Note that this number may be much higher than the * actual number of cosets, because multiple rows may be found correspond to a single coset long * after their construction. * * @param group the group. * @param subgroupGenerators generators of the subgroup. * @param sizeLimit the limit on the number of coset rows. */ public CosetAction(final FpGroup group, final List subgroupGenerators, final int sizeLimit) { // --- copy parameters to fields this.group = group; this.subgroupGenerators = Collections.unmodifiableList(subgroupGenerators); this.sizeLimit = sizeLimit; // --- extract generators and relators for group final List groupGenerators = group.getGenerators(); final List groupRelators = group.getRelators(); // --- set up translation tables this.ngens = 2 * groupGenerators.size(); this.idx2gen = new FreeWord[this.ngens]; this.gen2idx = new HashMap(); this.idx2invidx = new int[this.ngens]; int nu = 0; for (Iterator iter = groupGenerators.iterator(); iter.hasNext(); ) { final FreeWord g = (FreeWord) iter.next(); this.idx2gen[nu] = g; this.gen2idx.put(g, new Integer(nu)); this.idx2gen[nu + 1] = g.inverse(); this.gen2idx.put(g.inverse(), new Integer(nu + 1)); this.idx2invidx[nu] = nu + 1; this.idx2invidx[nu + 1] = nu; nu += 2; } // --- translate relators final List rels = new ArrayList(); for (Iterator iter = groupRelators.iterator(); iter.hasNext(); ) { final FreeWord r = (FreeWord) iter.next(); final int n = r.length(); for (int i = 0; i < n; ++i) { final FreeWord w = r.subword(i, n).times(r.subword(0, i)); rels.add(translateWord(w)); rels.add(translateWord(w.inverse())); } } // --- translate subgroup generators final List subgens = new ArrayList(); for (Iterator iter = subgroupGenerators.iterator(); iter.hasNext(); ) { final FreeWord generator = (FreeWord) iter.next(); subgens.add(translateWord(generator)); subgens.add(translateWord(generator.inverse())); } // --- set up a coset table with one dummy row and one row for the trivial coset this.table = new ArrayList(); this.table.add(new int[this.ngens]); this.table.add(new int[this.ngens]); // --- holds classes of rows known to correspond to the same coset IntPartition equivalences = new IntPartition(); // --- number of rows made invalid but not yet deleted int invalidRows = 0; // --- scan the table row by row, creating and deleting rows on the fly int i = 1; while (i < this.table.size()) { // --- proceed only if the current row is valid if (equivalences.find(i) != i) { ++i; continue; } // --- scan the current row final int row[] = (int[]) this.table.get(i); for (int j = 0; j < this.ngens; ++j) { // --- proceed only if the current column is empty if (row[j] != 0) { continue; } // --- log the result of this construction step if (LOGGING) { System.out.println("\ni = " + i + ", j = " + j); } // --- make a new row for the product with g final int newRow[] = new int[this.ngens]; this.table.add(newRow); // --- set the correspondences final int n = this.table.size(); row[j] = n - 1; newRow[this.idx2invidx[j]] = i; if (LOGGING) { System.out.println("after setting item:"); dumpTable(); } // --- scan relations to identify equivalent rows final LinkedList identify = new LinkedList(); for (Iterator iter = rels.iterator(); iter.hasNext(); ) { final int rel[] = (int[]) iter.next(); scanRelation(rel, n - 1, identify); } // --- scan subgroup generators final int one = equivalences.find(1); for (Iterator iter = subgens.iterator(); iter.hasNext(); ) { final int gen[] = (int[]) iter.next(); scanRelation(gen, one, identify); } if (LOGGING) { System.out.println("after scanning:"); dumpTable(); } // --- perform pending identifications invalidRows += performIdentifications(identify, equivalences); if (LOGGING) { System.out.println("after identifying:"); dumpTable(); } // --- quit if the limit on the number of rows is reached if (this.sizeLimit > 0 && n - invalidRows > this.sizeLimit) { throw new RuntimeException("table limit reached"); } // --- compress the table if necessary if (invalidRows > n / 2) { final int old2new[] = compressTable(equivalences); equivalences = new IntPartition(); i = old2new[i]; invalidRows = 0; if (LOGGING) { System.out.println("after compressing:"); dumpTable(); } } } // --- look at next row ++i; } // --- make a final cleanup compressTable(equivalences); if (LOGGING) { System.out.println("\nAfter final compression:"); dumpTable(); } // --- some finishing touches this.numberOfCosets = this.table.size() - 1; this.cosetRepresentatives = computeCosetRepresentatives(); }