Skip to content

Commit 209f41d

Browse files
committed
Fix biojava#321. Optimized completeGroup() for large groups.
Replaced the previous nested loop algorithm with a breadth-first search. This makes large-order groups (e.g. 40k permutations) finish in ms rather than hours.
1 parent c0b6294 commit 209f41d

1 file changed

Lines changed: 26 additions & 12 deletions

File tree

biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/PermutationGroup.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
package org.biojava.nbio.structure.symmetry.core;
2323

2424
import java.util.ArrayList;
25+
import java.util.HashSet;
2526
import java.util.List;
27+
import java.util.Set;
2628

2729
/**
2830
*
@@ -47,24 +49,36 @@ public int getOrder() {
4749

4850

4951
/**
52+
* Starts with an incomplete set of group generators in `permutations` and
53+
* expands it to include all possible combinations.
54+
*
5055
* Ways to complete group:
5156
* - combinations of permutations pi x pj
5257
* - combinations with itself p^k
5358
*
5459
*/
5560
public void completeGroup() {
56-
int n = permutations.size();
57-
for (int i = 0; i < permutations.size(); i++) {
58-
for (int j = i; j < permutations.size(); j++) {
59-
List<Integer> p = combine(permutations.get(i), permutations.get(j));
60-
addPermutation(p);
61-
// System.out.println("complete group: adding " + p);
62-
}
63-
}
64-
// repeat iteratively until no new permutation are created
65-
if (permutations.size() > n) {
66-
completeGroup();
67-
}
61+
// Copy initial set to allow permutations to grow
62+
List<List<Integer>> gens = new ArrayList<List<Integer>>(permutations);
63+
// Keep HashSet version of permutations for fast lookup.
64+
Set<List<Integer>> known = new HashSet<List<Integer>>(permutations);
65+
//breadth-first search through the map of all members
66+
List<List<Integer>> currentLevel = new ArrayList<List<Integer>>(permutations);
67+
while( currentLevel.size() > 0) {
68+
List<List<Integer>> nextLevel = new ArrayList<List<Integer>>();
69+
for( List<Integer> p : currentLevel) {
70+
for(List<Integer> gen : gens) {
71+
List<Integer> y = combine(p,gen);
72+
if(!known.contains(y)) {
73+
nextLevel.add(y);
74+
//bypass addPermutation(y) for performance
75+
permutations.add(y);
76+
known.add(y);
77+
}
78+
}
79+
}
80+
currentLevel = nextLevel;
81+
}
6882
}
6983

7084
public String toString() {

0 commit comments

Comments
 (0)