# Principled Programming / Tim Teitelbaum / Chapter 6. # Counting. def e6_1_1() -> None: """Count from 1 and don't stop.""" k: int = 1 while True: k += 1 def e6_1_2() -> None: """Count from 0 and don't stop.""" k: int = 0 while True: k += 1 # 1-D Indeterminate Enumeration. def e6_2_1() -> None: """Enumerate from start until !condition, but no further than maximum.""" start: int = 3 maximum: int = 5 condition: bool = True # k: int = start while k <= maximum and condition: k += 1 if k > maximum: # condition was True for all k in [start..maximum]. print("then ", maximum) else: # k is smallest in [start..maximum] for which condition is false. print("else", k) #i 1-D Indeterminate Enumeration. def e6_3_1() -> None: """Do whatever n times.using a while-statement.""" n: int = 3 k: int = 0 while k < n: # whatever print("whatever") # Increment k. k += 1 def e6_3_2() -> None: """Do whatever 10 times, using a while-statement.""" k: int = 0 while k < 10: # whatever print("whatever") # Increment k. k += 1 def e6_3_3() -> None: """Do whatever n times, using a for-statement.""" n: int = 3 for k in range(n): # whatever print("whatever") def e6_3_4() -> None: """ Do whatever n times, using a for-statement, and demonstrate that you can't break out of the iteration early by forcing the index to reach the end of the range. In fact, before running the program, there is already a warning that "local variable k is not used", so it is clear something is awry. """ n: int = 10 for k in range(n): # whatever print("whatever") # Break out of loop. if k == 3: k = n def e6_3_5() -> None: """ Do whatever n times, using a while-statement, and demonstrate that you can break out of the iteration with an additional condition at the head of the iteration, but not from within the body of the iteration """ n: int = 10 k: int = 0 while k < n and not(k == 3): # whatever print("whatever", k) # Increment k. k += 1 def e6_4_1() -> None: """ Enumeration Mod N from start. If you are trying to run the control variable k mod N, you necessarily either don't get started, or miss one and have to handle it separately outside the loop. """ start: int = 3 N: int = 5 k: int = start while not(k == (start-1) % N): print(k) k = (k + 1) % N print(k) def e6_4_2() -> None: """ Enumeration Mod N from start. You can just run the control variable not mod N, and mod-it-by-N when ready to enumerate it. """ start: int = 3 N: int = 5 k: int = start while k <= (start + N - 1): print(k % N) k += 1 # Sieve of Eratosthenes. def e6_5_1() -> None: """Print primes up to n.""" n: int = 15 # Initialize sieve to all prime. prime: list[bool] = [True] * (n + 1) # Print each prime in sieve, and cross out its multiples. for j in range(2, n+1): if prime[j]: print(j) for k in range(2 * j, n + 1, j): prime[k] = False; def e6_5_2() -> None: """Print primes up to n, but showing a silly "optimization".""" n: int = 15 prime: list[bool] = [True] * (n + 1) # Initialize sieve to all prime. for j in range(2, n+1): prime[j] = True # Print each prime in sieve, and cross out its multiples. for j in range(2, n + 1): if prime[j]: print(j) for k in range(2 * j, n + 1, j): if prime[k]: prime[k] = False # The test is a waste of time; just set it False regardless. def e6_5_3() -> None: """Print primes up to n, but showing another possibly silly "optimization".""" n: int = 15 prime: list[bool] = [True] * (n + 1) # Initialize sieve to all prime. for j in range(2, n+1): prime[j] = True; # Print each prime in sieve, and cross out its multiples. for j in range(2, n + 1): if prime[j]: print(j) if j <= (n / 2): # Is this really worthwhile. for k in range(2 * j, n + 1, j): prime[k] = False # 2-D Enumerations. def e6_6_1() -> None: """Enumerate ⟨r,c⟩ in [0..2][0..3] in row-major order.""" for r in range(3): for c in range(4): # whatever print(r, c) def e6_6_2() -> None: """Enumerate ⟨r,c⟩ in [0..height-1][0..width-1] in row-major order.""" height: int = 3 width: int = 4 for r in range(height): for c in range(width): # whatever print(r, c) def e6_6_3() -> None: # Enumerate ⟨r,c⟩ in [1..height][1..width] in row-major order. height: int = 3 width: int = 4 r: int c: int for r in range(1, height+1): for c in range(1, width+1): # whatever print(r, c) def e6_6_4() -> None: """ Enumerate ⟨r,c⟩ in [0..height-1][0..width-1] in row-major order, or until condition, and do whatever for each. For demonstration purposes, the condition is: r==2 and c==1 """ height: int = 3 width: int = 4 r: int = 0; c: int = 0 while r < height and not(r==2 and c==1): # whatever if c < width: c += 1 # Not the end of a row; go to next column. else: c = 0; r += 1 # The end of a row; go to start of next row. if r == height: # fail print("fail") else: # succeed print("succeed ", r, c) def e6_6_5() -> None: """Enumerate ⟨r,c⟩ in [0..height-1][0..width-1] in column-major order.""" height: int = 3 width: int = 4 for c in range(width): for r in range(height): # whatever print(r, c) def e6_6_6() -> None: """Enumerate ⟨r,c⟩ in a closed lower-triangular region of [0..size-1][0..size-1] in row-major order.""" size: int = 4 for r in range(size): for c in range(r+1): # whatever print(r, c) def e6_6_7() -> None: """Enumerate ⟨r,c⟩ in an open lower-triangular region of [0..size-1][0..size-1] in row-major order.""" size: int = 4 for r in range(1, size): for c in range(r): # whatever print(r, c) def e6_6_8() -> None: """ Unbounded diagonal enumeration, or until condition. For demonstration purposes, the condition is: d==4. """ d: int = 0 while not(d == 4): r: int = d for c in range(d+1): # whatever print(r, c) # decrement r r -= 1 d += 1 def e6_6_9() -> None: """n-by-n toroidal-diagonal enumeration in "magical order".""" n: int = 3 count: int = 1 A: list[list[int]] = [[0 for _ in range(n)] for _ in range(n)] r: int = 0; c: int = n // 2 for d in range(n): for k in range(n): # whatever A[r][c]=count; count += 1 # Output. print(r, c) # r = (r+n-1) % n; c = (c+1) % n # up 1 and right 1. r = (r+2) % n; c = (c+n-1) % n # down 2 and left 1. display(A, n) # Ramanujan Cubes. def e6_7_1() -> None: # Enumerate ⟨r,c⟩ through an open lower-triangular region of [0..12][0..12] in row-major order. for r in range(1,13): for c in range(r): # Keep track of having seen r^3+c^3. print(r, c, (r * r * r) + (c * c * c)) # Review the values of r^3+c^3 that arose. # See that Mr. R was right about 1729 occurring twice, # but it is not so easy to see that it is the smallest such. # We need to histogram the sums of cubes, and see that it is the smallest. # This will come in Chapter 12. # Rational Numbers. def e6_8_1() -> None: """Output n diagonals worth of fractions, including those equivalent as rationals.""" n: int = 4 d: int = 0 for _ in range(n): r = d for c in range(d+1): print( str(r+1) + "/" + str(c+1) ) r -= 1 d += 1 #Magic Squares. def e6_9_1(n: int): """Let M[N][N] be an N-by-N Magic Square, for odd N≥1.""" M: list[list[int]] = [[0 for _ in range(n)] for _ in range(n)] r: int = 0; c: int = n // 2 for k in range(1, n * n + 1): M[r][c] = k if M[(r + n - 1) % n][(c + 1) % n]==0: r = (r + n - 1) % n c = (c + 1) % n else: r = (r + 1) % n display(M, n) def display(a: list[list[int]], n: int) -> None: """Display an n-by-n array A.""" for r in range(n): for c in range(n): print((str(a[r][c]) + " ")[0:3], end='') print() # Uncomment out to run. #e6_1_1() #e6_1_2() #e6_2_1() #e6_3_1() #e6_3_2() #e6_3_3() #e6_3_4() #e6_3_5() #e6_4_1() #e6_4_2() #e6_5_1() #e6_5_2() #e6_5_3() #e6_6_1() #e6_6_2() #e6_6_3() #e6_6_4() #e6_6_5() #e6_6_6() #e6_6_7() #e6_6_8() #e6_6_9() #e6_7_1() #e6_8_1() #e6_9_1(3)