diff options
-rwxr-xr-x | generator.py | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/generator.py b/generator.py new file mode 100755 index 0000000..dd89f4f --- /dev/null +++ b/generator.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +from sys import argv, stdout + +class Tableau: + def __init__(self, dim, maxmaxim, debug=False): + self.dim = dim + self.maxmaxim = maxmaxim # the largest sets to consider -- this is bogus + self.debug = debug + + # Initialize the deck and its inverse map. + self.deck = [] + self.index = {} + for i in range(3**self.dim): + card = self.int2card(i) + self.deck.append(card) + self.index[card] = i + # Initialize the deck of cards which have internal order. + # TODO: they should have pointers them in an array + # (see nextPartition) + self.deckOrdered = [] + self.indexOrdered = {} + one, two = 0, 0 + for i in range((self.dim + 1)*(self.dim + 2)//2): + # the (self.dim+1)'th triangular number + # is the number of internally ordered cards + card = ("1"*one + "2"*two).rjust(self.dim, "0") + self.deckOrdered.append(card) + self.indexOrdered[card] = i + if one == 0: + one, two = two + 1, 0 + else: + one, two = one - 1, two + 1 + # Initialize the deck of cards with internal order and no 2s. + self.deckOrderedNo2 = [] + self.indexOrderedNo2 = {} + for i in range(self.dim + 1): + card = ("1"*i).rjust(self.dim, "0") + self.deckOrderedNo2.append(card) + self.indexOrderedNo2[card] = i + + # Initialize the tableau and its state values. + self.tableau = [self.deck[0]] + self.becameBoundary = [0 for i in range(self.dim-1)] + # len(self.tableau) when the index became a boundary + # 0 means it has not become a boundary yet + self.brokeTransposes = 0 + # len(self.tableau) when self.tableau[-1][0] first was nonzero + # 0 if it hasn't happened yet + self.noPop = True + + def int2card(self, num): + if num != int(num): + raise Exception("Number must be an integer.") + if num < 0: + raise Exception("Number must be nonnegative.") + if num >= 3**self.dim: + raise Exception("Number must be less than {}.".format(3**self.dim)) + strlist = [] + for i in range(self.dim): + strlist.append(str(num%3)) + num //= 3 + return ''.join(reversed(strlist)) + + def card2int(self, card): + return self.index[card] + + def nextPartition(self, partition, state): + """Returns the next valid partition and carry bool. + + This is where self.partitionState finally gets used. + (Which, indirectly, is when self.states gets used.) + + The state is either the number of partitions before it, + or is None to indicate the partition may be freely incremented. + + If there is no next partition in the lexicon, + then it zeros it out and returns True, + as a carry bit to increment the next partition. + """ + card = partition.rjust(self.dim, "0") + index = (self.index, self.indexOrdered, self.indexOrderedNo2)[state] + deck = (self.deck, self.deckOrdered, self.deckOrderedNo2)[state] + nextIndex = index[card] + 1 + if nextIndex == len(deck): + carry = True + else: + nextCard = deck[nextIndex] + if len(partition) == self.dim: + carry = False + else: + carry = nextCard[-len(partition)-1] == "1" + if carry: + nextPartition = "0"*len(partition) + else: + nextPartition = nextCard[-len(partition):] + return nextPartition, carry + + def nextCardWithPartitions(self): + nextCard = [] + state = 1 + boundaries = [index + 1 for index in reversed(range(self.dim - 1)) + if self.becameBoundary[index] != 0] + boundaries = [self.dim] + boundaries + [0] + if self.debug: + print("boundaries:", boundaries) + for i in range(len(boundaries)-1): + stop, start = boundaries[i], boundaries[i+1] + partition = self.tableau[-1][start:stop] + if i == len(boundaries) - 2 and self.brokeTransposes == 0: + state = 2 + nextPartition, carry = self.nextPartition(partition, state) + nextCard.append(nextPartition) + if not carry: break + else: return + if self.debug: + print("nextCard:", nextCard) + # nextCard = the attrs not incremented + the processed attrs + nextCard = self.tableau[-1][:boundaries[i+1]] \ + + "".join(reversed(nextCard)) + return nextCard + + def addCardWithPartitions(self, nextCard): + if self.brokeTransposes == 0: + if nextCard[0] == "1": + self.brokeTransposes = len(self.tableau) + self.noPop + elif nextCard[0] == "2": + raise Exception("First attribute must have value 1") + for index, addedWhen in enumerate(self.becameBoundary): + if addedWhen != 0: + continue + if nextCard[index] == nextCard[index + 1]: + continue + self.becameBoundary[index] = len(self.tableau) + self.noPop + self.tableau.append(nextCard) + + def increment(self): + """Appends the next appropriate card to tableau.""" + if (self.brokeTransposes == 0) or (0 not in self.becameBoundary): + nextCard = self.nextCardWithPartitions() + if nextCard == None: + return False + self.addCardWithPartitions(nextCard) + else: + nextIndex = self.card2int(self.tableau[-1]) + 1 + if nextIndex == len(self.deck): + return False + self.tableau.append(self.deck[nextIndex]) + if self.debug: + print("becameBoundary:", self.becameBoundary) + print("tableau:", self.tableau) + return True + + def revertToLen(self, length): + """Resets to the state when len(self.tableau) == length. + + Reverts self.becameBoundary and self.brokeTransposes. + """ + for index, addWhen in enumerate(self.becameBoundary): + if addWhen > length: + self.becameBoundary[index] = 0 + if self.brokeTransposes > length: + self.brokeTransposes = 0 + + def incrementWithPop(self): + """Increments in a way to replace the last card in tableau. + + Kind of gimmicky. + Sets all the partition variables as if the card had been popped, + then runs self.increment() without popping it, + then removes the card to pop afterwards.""" + self.noPop = False + if self.debug: + print("length:", len(self.tableau) - 1) + self.revertToLen(len(self.tableau) - 1) + while not self.increment(): + del self.tableau[-1] + if len(self.tableau) == 0: + exit() # Iteration Complete + self.revertToLen(len(self.tableau) - 1) + del self.tableau[-2] + self.noPop = True + + def main(self, outfile=stdout): + while True: + while self.increment(): + self.print(outfile) + while len(self.tableau) == self.maxmaxim: + self.incrementWithPop() + self.print(outfile) + self.incrementWithPop() + self.print(outfile) + + def print(self, outfile=stdout): + outstr = "[" + " ".join(self.tableau) + "]" + print(outstr, file=outfile) + +def main(): + if len(argv) <= 1: dim = 4 + if len(argv) > 1: dim = argv[1] + if len(argv) <= 2: maxmaxim = 4 + if len(argv) > 2: maxmaxim = argv[2] + outfile = open("generator.out", "w") + tableau = Tableau(dim, maxmaxim) + tableau.main(outfile) + +if __name__ == "__main__": main() |