def triples(): """ generates all Pythagorean triplets triplets x<y<z sorted by hypotenuse z, then longest side y """ prim=[] #list of primitive triples up to now key=lambda x:(x[2],x[1]) samez=SortedCollection(key=key) # temp triplets with same z buffer=SortedCollection(key=key) # temp for triplets with smaller z for pt in primitive_triples(): z=pt[2] if samez and z!=samez[0][2]: #flush samez while samez: yield samez.pop(0) samez.insert(pt) #build buffer of smaller multiples of the primitives already found for i,pm in enumerate(prim): p,m=pm[0:2] while True: mz=m*p[2] if mz < z: buffer.insert(tuple(m*x for x in p)) elif mz == z: # we need another buffer because next pt might have # the same z as the previous one, but a smaller y than # a multiple of a previous pt ... samez.insert(tuple(m*x for x in p)) else: break m+=1 prim[i][1]=m #update multiplier for next loops while buffer: #flush buffer yield buffer.pop(0) prim.append([pt,2]) #add primitive to the list
def sorted_iterable(iterable, key=None, buffer=100): """sorts an almost sorted (infinite) iterable :param iterable: iterable :param key: function used as sort key :param buffer: int size of buffer. elements to swap should not be further than that """ from Goulib.container import SortedCollection b=SortedCollection(key=key) for x in iterable: if len(b)>=buffer: yield b.pop(0) b.insert(x) for x in b: yield x # this never happens if iterable is infinite
def sorted_iterable(iterable, key=None, buffer=100): """sorts an "almost sorted" (infinite) iterable :param iterable: iterable :param key: function used as sort key :param buffer: int size of buffer. elements to swap should not be further than that """ key = key or identity from Goulib.container import SortedCollection b = SortedCollection(key=key) for x in iterable: if len(b) >= buffer: res = b.pop(0) yield res b.insert(x) for x in b: # this never happens if iterable is infinite yield x
def primitive_triples(): """ generates primitive Pythagorean triplets x<y<z sorted by hypotenuse z, then longest side y through Berggren's matrices and breadth first traversal of ternary tree :see: https://en.wikipedia.org/wiki/Tree_of_primitive_Pythagorean_triples """ key = lambda x: (x[2], x[1]) triples = SortedCollection(key=key) triples.insert([3, 4, 5]) A = [[1, -2, 2], [2, -1, 2], [2, -2, 3]] B = [[1, 2, 2], [2, 1, 2], [2, 2, 3]] C = [[-1, 2, 2], [-2, 1, 2], [-2, 2, 3]] while triples: (a, b, c) = triples.pop(0) yield (a, b, c) # expand this triple to 3 new triples using Berggren's matrices for X in [A, B, C]: triple = [ sum(x * y for (x, y) in zip([a, b, c], X[i])) for i in range(3) ] if triple[0] > triple[1]: # ensure x<y<z triple[0], triple[1] = triple[1], triple[0] triples.insert(triple)
def primitive_triples(): """ generates primitive Pythagorean triplets x<y<z sorted by hypotenuse z, then longest side y through Berggren's matrices and breadth first traversal of ternary tree :see: https://en.wikipedia.org/wiki/Tree_of_primitive_Pythagorean_triples """ key=lambda x:(x[2],x[1]) triples=SortedCollection(key=key) triples.insert([3,4,5]) A = [[ 1,-2, 2], [ 2,-1, 2], [ 2,-2, 3]] B = [[ 1, 2, 2], [ 2, 1, 2], [ 2, 2, 3]] C = [[-1, 2, 2], [-2, 1, 2], [-2, 2, 3]] while triples: (a,b,c) = triples.pop(0) yield (a,b,c) # expand this triple to 3 new triples using Berggren's matrices for X in [A,B,C]: triple=[sum(x*y for (x,y) in zip([a,b,c],X[i])) for i in range(3)] if triple[0]>triple[1]: # ensure x<y<z triple[0],triple[1]=triple[1],triple[0] triples.insert(triple)
def triples(): """ generates all Pythagorean triplets triplets x<y<z sorted by hypotenuse z, then longest side y """ prim = [] #list of primitive triples up to now key = lambda x: (x[2], x[1]) samez = SortedCollection(key=key) # temp triplets with same z buffer = SortedCollection(key=key) # temp for triplets with smaller z for pt in primitive_triples(): z = pt[2] if samez and z != samez[0][2]: #flush samez while samez: yield samez.pop(0) samez.insert(pt) #build buffer of smaller multiples of the primitives already found for i, pm in enumerate(prim): p, m = pm[0:2] while True: mz = m * p[2] if mz < z: buffer.insert(tuple(m * x for x in p)) elif mz == z: # we need another buffer because next pt might have # the same z as the previous one, but a smaller y than # a multiple of a previous pt ... samez.insert(tuple(m * x for x in p)) else: break m += 1 prim[i][1] = m #update multiplier for next loops while buffer: #flush buffer yield buffer.pop(0) prim.append([pt, 2]) #add primitive to the list