mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
172 lines
3.9 KiB
Swift
172 lines
3.9 KiB
Swift
/// This file implements algorithms for enumerating all monoid presentations
|
|
/// up to a given length.
|
|
|
|
func nextSymbol(_ s: inout Symbol, alphabet: Int) -> Bool {
|
|
precondition(alphabet > 0)
|
|
if s == alphabet - 1 {
|
|
s = 0
|
|
return true
|
|
}
|
|
s += 1
|
|
return false
|
|
}
|
|
|
|
func nextWord(_ word: inout Word, alphabet: Int) -> Bool {
|
|
var carry = true
|
|
for i in word.indices.reversed() {
|
|
carry = nextSymbol(&word[i], alphabet: alphabet)
|
|
if !carry { break }
|
|
}
|
|
return carry
|
|
}
|
|
|
|
func nextRule(_ rule: inout Rule, alphabet: Int) -> Bool {
|
|
if nextWord(&rule.rhs, alphabet: alphabet) {
|
|
rule.rhs = Word(repeating: 0, count: rule.rhs.count)
|
|
if nextWord(&rule.lhs, alphabet: alphabet) {
|
|
rule.lhs = Word(repeating: 0, count: rule.lhs.count)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func nextPresentation(_ p: inout Presentation, alphabet: Int) -> Bool {
|
|
precondition(!p.rules.isEmpty)
|
|
var carry = true
|
|
for i in p.rules.indices.reversed() {
|
|
carry = nextRule(&p.rules[i], alphabet: alphabet)
|
|
if !carry { break }
|
|
}
|
|
return carry
|
|
}
|
|
|
|
struct RuleShape {
|
|
var lhs: Int
|
|
var rhs: Int
|
|
|
|
var rule: Rule {
|
|
return Rule(lhs: Word(repeating: 0, count: lhs),
|
|
rhs: Word(repeating: 0, count: rhs))
|
|
}
|
|
}
|
|
|
|
struct PresentationShape {
|
|
var rules: [RuleShape]
|
|
|
|
func presentation(alphabet: Int) -> Presentation {
|
|
return Presentation(alphabet: alphabet,
|
|
rules: rules.map { $0.rule })
|
|
}
|
|
}
|
|
|
|
func enumerateAll(alphabet: Int, shapes: [PresentationShape], output: Bool)
|
|
-> [Presentation] {
|
|
var filteredLHS = 0
|
|
var filteredRHS = 0
|
|
var filteredSymmetry = 0
|
|
var total = 0
|
|
|
|
var instances: [Presentation] = []
|
|
var unique: Set<Presentation> = []
|
|
|
|
let perms = allPermutations(alphabet)
|
|
|
|
for shape in shapes {
|
|
var p = shape.presentation(alphabet: alphabet)
|
|
var done = false
|
|
|
|
loop: while !done {
|
|
defer {
|
|
done = nextPresentation(&p, alphabet: alphabet)
|
|
}
|
|
|
|
total += 1
|
|
|
|
for n in 0 ..< p.rules.count - 1 {
|
|
if compare(p.rules[n].lhs, p.rules[n + 1].lhs, order: .shortlex) != .lessThan {
|
|
filteredLHS += 1
|
|
continue loop
|
|
}
|
|
}
|
|
|
|
for rule in p.rules {
|
|
precondition(rule.rhs.count <= rule.lhs.count)
|
|
if compare(rule.rhs, rule.lhs, order: .shortlex) != .lessThan {
|
|
filteredRHS += 1
|
|
continue loop
|
|
}
|
|
}
|
|
|
|
if unique.contains(p) {
|
|
filteredSymmetry += 1
|
|
continue
|
|
}
|
|
|
|
for perm in perms {
|
|
let permuted = p.permuted(perm)
|
|
unique.insert(permuted.sorted(order: .shortlex))
|
|
}
|
|
|
|
instances.append(p)
|
|
}
|
|
}
|
|
|
|
if output {
|
|
print("# Total \(total)")
|
|
print("# Discarded lhs:\(filteredLHS),rhs:\(filteredRHS),"
|
|
+ "symmetry:\(filteredSymmetry)")
|
|
}
|
|
|
|
return instances
|
|
}
|
|
|
|
func ruleShapes(_ n: Int) -> [RuleShape] {
|
|
precondition(n > 0)
|
|
var result: [RuleShape] = []
|
|
for i in 0 ..< n {
|
|
let j = n - i
|
|
|
|
// Don't consider rules with a shorter left-hand side.
|
|
if j < i { continue }
|
|
|
|
// Don't consider rules of the form x=1 or x=y where x, y are generators.
|
|
if j == 1 && i <= 1 { continue }
|
|
|
|
result.append(RuleShape(lhs: j, rhs: i))
|
|
}
|
|
return result
|
|
}
|
|
|
|
func presentationShapes(rules: Int, ofLength n: Int) -> [PresentationShape] {
|
|
precondition(n > 0)
|
|
precondition(rules > 0)
|
|
|
|
if rules == 1 {
|
|
return ruleShapes(n).map {
|
|
PresentationShape(rules: [$0])
|
|
}
|
|
}
|
|
|
|
var result: [PresentationShape] = []
|
|
for i in 1 ..< n {
|
|
let next = presentationShapes(rules: rules - 1, ofLength: i)
|
|
for x in ruleShapes(n - i) {
|
|
for y in next {
|
|
if x.lhs <= y.rules.first!.lhs {
|
|
result.append(PresentationShape(rules: [x] + y.rules))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func presentationShapes(rules: Int, upToLength n: Int) -> [PresentationShape] {
|
|
var shapes: [PresentationShape] = []
|
|
for i in 1 ... n {
|
|
shapes.append(contentsOf: presentationShapes(rules: rules, ofLength: i))
|
|
}
|
|
return shapes
|
|
}
|