From de00d6a9e23693ac4a855d62d7e3967b72c26e41 Mon Sep 17 00:00:00 2001 From: snightin-sudo Date: Fri, 5 Sep 2025 15:13:03 -0400 Subject: [PATCH 1/3] Update main.py --- Finished Code/python/src/variables/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Finished Code/python/src/variables/main.py b/Finished Code/python/src/variables/main.py index 0c2a4f4..ac72f90 100644 --- a/Finished Code/python/src/variables/main.py +++ b/Finished Code/python/src/variables/main.py @@ -15,7 +15,7 @@ def main(): # Let's declare some variables j = 14 #Python gives this type int x = -2.3 #type: float - yo_world = "Hi" #type: string + yo_world = "Hi" # type: ignore #type: string statement = True # type: bool #Note: multi-word variable names use snake_case From c33eff5a208e94e91408b4feef5d4ce5158d2fd3 Mon Sep 17 00:00:00 2001 From: snightin-sudo Date: Sat, 13 Sep 2025 11:57:15 -0400 Subject: [PATCH 2/3] Squashed commit of the following: commit 07a91a7505863dc7984cba8242486aced6447597 Author: Phillip Compeau Date: Thu Sep 11 17:06:03 2025 -0400 finishing code for ch 1 commit 5c75df815274dbcb54dc2b85805a206dcca4a5cb Author: Phillip Compeau Date: Thu Sep 11 16:21:31 2025 -0400 add min int value function to skew commit 9c1d53fececebfc6a8c326c2e6f92594814e4ffe Author: Phillip Compeau Date: Thu Sep 11 15:45:02 2025 -0400 minor commit 51ebba5363ae8bc0201e9a193c3060558b431d7d Author: Phillip Compeau Date: Thu Sep 11 15:43:42 2025 -0400 update clumps starter codd commit 26795494b75b595dd127cd90c7edf1f2a2b1394a Author: Phillip Compeau Date: Thu Sep 11 15:43:04 2025 -0400 update skew starter code --- Finished Code/python/src/clumps/main.py | 129 +++++++++++ Finished Code/python/src/dictionaries/main.py | 56 +++++ Finished Code/python/src/skew/main.py | 202 ++++++++++++++++++ Finished Code/python/src/skew/skewDiagram.png | Bin 0 -> 25354 bytes Starter Code/.DS_Store | Bin 10244 -> 6148 bytes Starter Code/clumps/main.py | 32 +-- Starter Code/skew/main.py | 62 +++--- 7 files changed, 416 insertions(+), 65 deletions(-) create mode 100644 Finished Code/python/src/clumps/main.py create mode 100644 Finished Code/python/src/skew/main.py create mode 100644 Finished Code/python/src/skew/skewDiagram.png diff --git a/Finished Code/python/src/clumps/main.py b/Finished Code/python/src/clumps/main.py new file mode 100644 index 0000000..ab3c9b7 --- /dev/null +++ b/Finished Code/python/src/clumps/main.py @@ -0,0 +1,129 @@ +import requests + +def main(): + print("Finding clumps.") + + text = "AAAACGTCGAAAA" + k = 3 + window_length = 4 + t = 2 + + # should print "AAA" + print(find_clumps(text, k, window_length, t)) + + url = "https://bioinformaticsalgorithms.com/data/realdatasets/Replication/E_coli.txt" + + response = requests.get(url) + + response.raise_for_status() # give us an error if there was a problem + + genome = response.text + + print("Genome has length", len(genome), "nucleotides.") + + # call the clump finding algorithm! + k = 9 + window_length = 500 + t = 3 + + patterns = find_clumps(genome, k, window_length, t) + + print("Success!") + + print("We found", len(patterns), "total patterns that form clumps.") + + +""" +FindClumps(text, k, L, t) + patterns ← an array of strings of length 0 + n ← length(text) + for every integer i between 0 and n − L + window ← text[i, i + L] + freqMap ← FrequencyTable(window, k) + for every key s in freqMap + if freqMap[s] ≥ t and Contains(patterns, s) = false + patterns ← append(patterns, s) + return patterns +""" + +def find_clumps(text: str, k: int, window_length: int, t: int) -> list[str]: + """ + Finds a list of strings representing all k-mers that appear at least t times + in a window of given length in the string. + + Parameters: + - text (str): The input string. + - k (int): The k-mer length. + - window_length (int): Length L of the sliding window. + - t (int): Frequency threshold within a window. + + Returns: + - list[str]: All distinct k-mers forming (L, t)-clumps in text. + """ + patterns = [] + n = len(text) + + # range over all windows (i.e., all substrings having length window_length in text) + for i in range(n-window_length+1): + if i % 10000 == 0: + print(i) + current_window = text[i:i+window_length] + freq_map = frequency_table(current_window, k) + + # find any k-mers in table that occur at least t times + for s, occurrences in freq_map.items(): + # does it occur at least t times? AND have we not seen it before + if occurrences >= t and (s not in patterns): + # append pattern to list + patterns.append(s) + + return patterns + +def frequency_table(text: str, k: int) -> dict[str, int]: + """ + Builds a frequency table of all k-mers of length k in the given text, + including overlaps. + + Parameters: + - text (str): The input string. + - k (int): The size of the k-mers. + + Returns: + - dict[str, int]: A dictionary mapping each k-mer to its frequency. + """ + if k <= 0: + raise ValueError("k is not positive.") + if k > len(text): + return [] + + # declare a blank map + freq_map: dict[str, int] = {} + + n = len(text) + + # range over all k-mer substrings of text + for i in range(n-k+1): + # grab current pattern of length k + pattern = text[i:i+k] + + # does pattern exist in freq_map?? + # if not, then we create it as an entry + + """ + CLASSIC WAY + if pattern not in freq_map: + freq_map[pattern] = 1 + else: + # we have seen it! + freq_map[pattern] += 1 + """ + + # shortcut approach using get() + # get() takes two parameters: the key to retrieve, and a default value to assign it if it doesn't exist as a key + freq_map[pattern] = freq_map.get(pattern, 0) + 1 + + + return freq_map + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Finished Code/python/src/dictionaries/main.py b/Finished Code/python/src/dictionaries/main.py index 2ec21b1..8abab5a 100644 --- a/Finished Code/python/src/dictionaries/main.py +++ b/Finished Code/python/src/dictionaries/main.py @@ -28,6 +28,62 @@ def main(): print("Number of states in dictionary after Florida deletion:", len(polls)) + # list and dictionary literals + symbols = ["A", "C", "G", "T"] + + electoral_votes: dict[str, int] = { + "Pennsylvania": 20, + "Ohio": 18, + "Texas": 38 + } + + update_votes(electoral_votes) + + # are dictionaries pass by value or reference???? + + print("After function call, printing electoral votes.") + print(electoral_votes) + + # let's print things more nicely + # when ranging over a list, we get the values of the list + # with dictionaries, we get the KEYS of the list + for state_name in electoral_votes: + print("The number of electoral votes in", state_name, "is", electoral_votes[state_name]) + + # we also have double ranging for dictionaries + for state_name, votes in electoral_votes.items(): + print("The number of electoral votes in", state_name, "is", votes) + + # let's instead get these in alphabetical order. but how? + + # for a dictionary dict, Python gives us an operator dict.keys() that produces the dictionary's keys, which we can convert to a list + state_names = list(electoral_votes.keys()) + print(state_names) + + # Python gives us a built in sorting algorithm that sorts a list into alphabetical order :) + state_names.sort() + + print(state_names) + + # now we can print the dictionary by ranging over the sorted keys and printing the associated values + + for state in state_names: + print("The number of electoral votes in", state, "is", electoral_votes[state]) + + + + + +def update_votes(votes: dict[str, int]) -> None: + """ + Update votes according to 2024 values. + """ + votes["Pennsylvania"] = 19 + votes["Ohio"] = 17 + votes["Texas"] = 40 + + + diff --git a/Finished Code/python/src/skew/main.py b/Finished Code/python/src/skew/main.py new file mode 100644 index 0000000..de4294a --- /dev/null +++ b/Finished Code/python/src/skew/main.py @@ -0,0 +1,202 @@ +from matplotlib import pyplot + +import requests + +def main(): + print("Building a skew array.") + + # --- Tiny local demo (uncomment after implementing functions) --- + demo_genome = "CATGGGCATCGGCCATACGCC" + arr = skew_array(demo_genome) + print("Demo skew array length:", len(arr)) + print("First few values:", arr[:10]) + print("Minimum skew indices (demo):", minimum_skew(demo_genome)) + + # --- E. coli genome experiment & plotting (uncomment to run) --- + url = "https://bioinformaticsalgorithms.com/data/realdatasets/Replication/E_coli.txt" + + response = requests.get(url) + response.raise_for_status() + + genome = response.text + + print("The number of nucleotides in E. coli genome is " + str(len(genome))) + + ecoli_skew_array = skew_array(genome) + min_skew_positions = minimum_skew(genome) + if len(min_skew_positions) == 0: + raise RuntimeError("No minimum positions found (unexpected).") + + first_pos = min_skew_positions[0] + print( + "The minimum skew value of " + + str(ecoli_skew_array[first_pos]) + + " occurs at positions " + + str(min_skew_positions) + ) + + # Plot (requires matplotlib) + + draw_skew(ecoli_skew_array) + print("Skew diagram drawn! Exiting normally.") + + + +""" +Skew(symbol) + if symbol = 'G' + return 1 + else if symbol = 'C' + return -1 + return 0 +""" + +""" +SkewArray(genome) + n ← length(genome) + array ← array of length n + 1 + array[0] ← 0 + for every integer i between 1 and n + array[i] = array[i-1] + Skew(genome[i-1]) + return array +""" + +def skew_array(genome: str) -> list[int]: + """ + Returns the skew array for `genome`, where skew[i] is the difference + (# of 'G') - (# of 'C') in genome[0:i]. + + Parameters: + - genome (str): DNA string. + + Returns: + - list[int]: Skew array of length len(genome) + 1. + + Raises: + - ValueError: If genome is empty. + """ + + if len(genome) == 0: + raise ValueError("Zero length genome given.") + + n = len(genome) + + # define a skew array + skew_array = [0] * (n+1) + + # range over genome, and set skew_array[i-1] using previous value + for i in range(1, n+1): + skew_array[i] = skew_array[i-1] + skew(genome[i-1]) + + return skew_array + + +def skew(symbol: str) -> int: + """ + Returns 1 if symbol is 'G'/'g', -1 if 'C'/'c', else 0. + + Parameters: + - symbol (str): Single-character string. + + Returns: + - int: Skew contribution for this symbol. + + Raises: + - ValueError: If `symbol` is not length 1. + """ + + if len(symbol) != 1: + raise ValueError("String given must be single character.") + + # return 1 if G or g + if symbol == "G" or symbol == "g": + return 1 + elif symbol == "C" or symbol == "c": + return -1 + else: + return 0 # we could do better + +""" +MinimumSkew(genome) + indices ← array of integers of length 0 + n ← length(genome) + array ← SkewArray(genome) + m ← MinIntegerArray(array) + for every integer i between 0 and n + if array[i] = m + indices = append(indices, i) + return indices +""" + +def minimum_skew(genome: str) -> list[int]: + """ + Returns all indices i (0..len(genome)) where the skew array achieves + its minimum value. + + Parameters: + - genome (str): DNA string. + + Returns: + - list[int]: Indices where skew is minimal. + + Raises: + - ValueError: If genome is empty. + """ + + if len(genome) == 0: + raise ValueError("Empty genome given.") + + # create list of indices + indices = [] + + skew_arr = skew_array(genome) + + # find minimum value + min_val = min_integer_array(skew_arr) + + # range over the skew array, and find all indices where val = m + n = len(skew_arr) + for i in range(n): + if skew_arr[i] == min_val: + indices.append(i) + + return indices + + +def min_integer_array(a:list[int]) -> int: + """" + Returning the minimum value in a list of integers. + """ + + if len(a) == 0: + raise ValueError("Error: empty list given.") + + m = 0 + + # iterate over list, updating m if we find a smaller value + + for i, val in enumerate(a): + # ranges over the values in a list + # if we find a smaller value than the current min + # OR we are at the first element, update m + if val < m or i == 0: + m = val + + return m + + +def draw_skew(skew_list: list[int]) -> None: + """ + draw_skew draws a skew diagram using a skew_array output. + + """ + if len(skew_list) == 0: + raise ValueError("skew_list is empty") + pyplot.plot(skew_list) + pyplot.title("Skew Diagram") + pyplot.xlabel("Genome Position") + pyplot.ylabel("Skew Value") + pyplot.savefig("skewDiagram.png") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Finished Code/python/src/skew/skewDiagram.png b/Finished Code/python/src/skew/skewDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..6e3ff8def535d7ab153affbdaa3708f243b7b5cf GIT binary patch literal 25354 zcmdSBWmr`0_cpv~5flUkQA&Y9q?D8#Fz8T_E|Ko;8q`}wknU7zDT$#|x}_UNx`yt7 z;koAi{hsGI-uL-`e80ROI5=Qt_P+MD*Iw&f=XtIPdZ{9N?dqMY5CmP5mwT=TLHGy= z!b4pl2LBNpm|g_GL|tEKyQ({wyLuQqn?cIPu8y`2uC`WhncdBtU924J`FS2c;t}Lx zwsduMbP?s{wfjHs;Bj!a;MKucih-k$I?Cy|KoEs7?guXio^1s|Z{6jeOTYF^M$eFV zzBU_e+1_T=xpBl-g28t3W5;OGyE$MMEOPz!UNkuPRa~Egt+(r zmk;qN#d7InILy`0Q|Ol4S_wfrB&-O?e!SdnYVrFg#>l};MMZ7x_-W^EZs#!rkIpHF z2JZTAvSExc5jTe_=cP#JrLKgPgApww`KM3c4c)_+`gpZ-e2QR4I8Uo6R z!()3^t<3V3i0{d-e1jTIm})B5#n~aXQ8>4r(CJPyMKAUrGTO!Cxq!IsdQ2Z{pzhFd zukf5)s<>DFo? zZC~%QQ?si?8#jMUSacuF*BM3r`SX(G$IYOiponA<7ty_O=$ux$5gZA7fyvZGT6adm zH7Xtd+W0rXbfl%F%a`ZDQWW-=dzF7giFw$s{rUcWbG*2@8jG%&OU#-q(5uj0Da+OD zcUvFsbiaJ4@l$T4FU8^P^csWc>&Y@JmQsuU*g1a;_lP9I$;pY&c~LG`t0-0ev!J`* zbxzHEIrshs?3rS!=RB!;dQOqv@z#u4cPuvyOUG|Mo|uIc(KT8)LQf@)%@?;b@{jqS z@5*|e{Qacdn>T6*?vxra`RzB>yb@L0POE?JRjs7@^wbLtsHTXHSl2f!go-KEPJV#9 zEcYb&7eFUGAU=hkM}53@SEvIV)8WL&$ZP3VltA6_tdFMp?j`mZ9<^ijW3N8|t1c6A z`<|G`Rf8kF;VGq!{{=Sgvs|$^4N!i?S{)(i!{Gc)_z@?2KS9o?g@$cg@sIm8h4nyFB&

bYMN-s3rThmLBel3BiRa3s5hm8_S55nrX7@H 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 IQ&;c)1M5Hs8~^|S literal 0 HcmV?d00001 diff --git a/Starter Code/.DS_Store b/Starter Code/.DS_Store index 3255679f42a532d2c88f3a870416b00da73cfa79..a1ab1f0324ebfe1f987ff32d542b5aedc968a475 100644 GIT binary patch literal 6148 zcmeHKy-ve05dK^$)QSpqWVFQAiH>Zc3KL@=ps0T!(U3x^x<>3g1v~=pz`{fEoo%H_ zQ)nlI(4BPtobz3L{^I0f0H(JbcY!v5234@uWV1zNT(ly!U}+JJyT=@h*-f`UN|SlT zTMd7a0eN%dFv$Hv#q;Wi)r9;{qZ>NLT=kt$?s?T_*&-}KyPh|h$7*jlA zf(Pa@!9AWZzzQjC(lmTTx8Q7Zv)@+f+kw)ov`oz<%m`c#3*3qkrs;ap+p~Q!V$yxaN2F~ivngIeK?GpnfD1Zn{YxgZg$$O zbBBpMYO4$=17!vd{AF9}|K<1R|8kICDFe#Dzhc1D<9^)Zl0t2*EKX{zrCw7-#4q!h khp^*HF@2>JpHQ99Zlyzv0%jg*q3Dl*qd^;G;8z*=0>f@|X8-^I literal 10244 zcmeHMzmFS56n>ld?sk<6x+oBl0%;{EQk-Pp<&r3(F+N975ENl96o3w|cXM9YAI7_m zbvh2YL;?vU=%C@7%&VN1`Gp+ zfv151yt6sk=L%`=h5^HXVPL`luMaLRmUSsdg%nE%Zej}nSwXQ#c*Z_J*tk;Gr5qJf zn4-;M_h3m=OKvf&!W{K3t3%eM92K%KC#x_gOZIHZ9f~D-hn*|b$*LF9+zkVUfmsH4 z@9t28+SI2+-M??OI%(W13|_cUt`(=vrWd6iYVBI&e;hR*yfRPIUsAKzReQd}09MGO zltS_;iw@M;S?qo@vKr4xN}@p z+JjbrNN0HNQ5T#>_=R}xz$S(apf^Bm6Zwv8BY`zryb8@+obPzZ-9bAk9pK)EWsJH6 zxqB$<15XF}03|sjBg<%;YPfb_*+QPj8{_R`o!^CxkLT(%m+7(X5^c?gRqPH&W zB7wWFj}7OeaxFDJd*4jrQ_`LqrNx>hu_|fre;ToJPsed9sYP7YdF+!UB_f~l@F&VzC-71!nOwb3-yo{DX; zrjD=9_}1w*#yQWL1IPsPh38vGUyZCU9zR~Bt76^$oTVJ`1`#feQ z&-AufXLzRWid>H}Z9COw5#Yy@Z`+#pr`OOJ;^z=Eh3tZHP z(ArOnwbk%k`eibd7PPMhXgLctMDj!Zf(#Ka)ExvUz!V5EyassY*9Mkz-H%H=6_&74 z{rUZ`i9btOp1h?0ou%%d_;|4K>fx8S4?p>J7wF!ce+k~q=&0BqemnV)DA7AXx=61C z*9sW!VLHdu)(};${0Kx!t%~Kzz2SG0kD7_SIu6P;wEin!q63o*1BL;^fMMYDGH|wV z-R1NDTl4?_KfMGQ&kX~ofB~!0Y&9EjbiB`*_L3ERLJAYyScS{QaXd17 z9DhZY)mU;ueO<~?A%!{0g*jw#n*X2w8K9hPK4KtzN-?!x*FMV0?EnAyyg=P#nEgMF MIP@X(l list[str]: """ Finds a list of strings representing all k-mers that appear at least t times @@ -47,24 +39,6 @@ def find_clumps(text: str, k: int, window_length: int, t: int) -> list[str]: pass -def contains(patterns: list[str], s: str) -> bool: - """ - Returns True if s appears in the list `patterns`, else False. - - Parameters: - - patterns (list[str]): A list of strings. - - s (str): Query string. - - Returns: - - bool: True if s ∈ patterns, else False. - - Hint: - - You may use the `in` operator or a manual loop, per the code along. - """ - # TODO: Implement this function - pass - - def frequency_table(text: str, k: int) -> dict[str, int]: """ Builds a frequency table (dictionary) of all k-mers of length k in `text`, diff --git a/Starter Code/skew/main.py b/Starter Code/skew/main.py index 5d21e86..01b342a 100644 --- a/Starter Code/skew/main.py +++ b/Starter Code/skew/main.py @@ -1,6 +1,6 @@ from matplotlib import pyplot -import urllib.request +import requests def main(): print("Building a skew array.") @@ -14,29 +14,14 @@ def main(): print("Minimum skew indices (demo):", minimum_skew(demo_genome)) """ - # --- E. coli genome experiment & plotting (uncomment to run) --- - """ - demo_genome = "CATGGGCATCGGCCATACGCC" - arr = skew_array(demo_genome) - print("Demo skew array length:", len(arr)) - print("First few values:", arr[:10]) - print("Minimum skew indices (demo):", minimum_skew(demo_genome)) - """ - # --- E. coli genome experiment & plotting (uncomment to run) --- """ url = "https://bioinformaticsalgorithms.com/data/realdatasets/Replication/E_coli.txt" - contents = urllib.request.urlopen(url) - # Check status code - if contents.getcode() != 200: - raise urllib.error.URLError("Bad status code") + response = requests.get(url) + response.raise_for_status() - # Read and decode - contents = contents.read() - genome = contents.decode('utf-8') - if not genome: - raise ValueError("Downloaded genome sequence is empty.") + genome = response.text print("The number of nucleotides in E. coli genome is " + str(len(genome))) @@ -125,23 +110,6 @@ def skew(symbol: str) -> int: pass -def min_integer_array(values: list[int]) -> int: - """ - Returns the minimum value in an integer list. - - Parameters: - - values (list[int]): List of ints. - - Returns: - - int: Minimum element of `values`. - - Raises: - - ValueError: If `values` is empty. - """ - # TODO: Implement this function - pass - - def minimum_skew(genome: str) -> list[int]: """ Returns all indices i (0..len(genome)) where the skew array achieves @@ -160,6 +128,28 @@ def minimum_skew(genome: str) -> list[int]: pass +def min_integer_array(a:list[int]) -> int: + """" + Returning the minimum value in a list of integers. + """ + + if len(a) == 0: + raise ValueError("Error: empty list given.") + + m = 0 + + # iterate over list, updating m if we find a smaller value + + for i, val in enumerate(a): + # ranges over the values in a list + # if we find a smaller value than the current min + # OR we are at the first element, update m + if val < m or i == 0: + m = val + + return m + + def draw_skew(skew_list: list[int]) -> None: """ draw_skew draws a skew diagram using a skew_array output. From 7a1c47e7ca6ed1d65baf185995e9a0823b441c9c Mon Sep 17 00:00:00 2001 From: snightin-sudo Date: Sat, 13 Sep 2025 12:38:17 -0400 Subject: [PATCH 3/3] updates --- .../__pycache__/election_io.cpython-313.pyc | Bin 0 -> 1681 bytes .../recitation/election/data/conventions.csv | 51 +++++ .../src/recitation/election/data/debates.csv | 51 +++++ .../recitation/election/data/earlyPolls.csv | 51 +++++ .../election/data/electoralVotes.csv | 51 +++++ .../src/recitation/election/election_io.py | 38 ++++ .../python/src/recitation/election/main.py | 22 ++ .../primes/__pycache__/main.cpython-313.pyc | Bin 0 -> 5183 bytes .../primes/__pycache__/main.cpython-314.pyc | Bin 0 -> 6076 bytes .../python/src/recitation/primes/main.py | 200 ++++++++++++++++++ .../src/recitation/recitation1starter.py | 95 +++++++++ 11 files changed, 559 insertions(+) create mode 100644 Finished Code/python/src/recitation/election/__pycache__/election_io.cpython-313.pyc create mode 100644 Finished Code/python/src/recitation/election/data/conventions.csv create mode 100644 Finished Code/python/src/recitation/election/data/debates.csv create mode 100644 Finished Code/python/src/recitation/election/data/earlyPolls.csv create mode 100644 Finished Code/python/src/recitation/election/data/electoralVotes.csv create mode 100644 Finished Code/python/src/recitation/election/election_io.py create mode 100644 Finished Code/python/src/recitation/election/main.py create mode 100644 Finished Code/python/src/recitation/primes/__pycache__/main.cpython-313.pyc create mode 100644 Finished Code/python/src/recitation/primes/__pycache__/main.cpython-314.pyc create mode 100644 Finished Code/python/src/recitation/primes/main.py create mode 100644 Finished Code/python/src/recitation/recitation1starter.py diff --git a/Finished Code/python/src/recitation/election/__pycache__/election_io.cpython-313.pyc b/Finished Code/python/src/recitation/election/__pycache__/election_io.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5171c2fa36eed97a48271199f9552efbdee4d315 GIT binary patch literal 1681 zcmc&!&1(}u6raszQ?s_(k6>-6I#p2vHP}K9iWQ1lq>_q_5upoV*-W})w>!(sv?ZQ; zj3`pSu-?4-X9!-rdnjvfg5XV!Q1IlN-AyARiXiyHyu5keFL}Rd_w|_wXkNZ{pQI6b zuPz-*B|`fk2v1Q3RkW*!qe?1|xK`1DrxvwB`lE82bF{=;eP!V2aN1kIo}z_aTM6!p zd~HG5BdS8)Qc^30{L}*U5!1ZN^AjCK)l@0T=j&B{2wfS4eCcYsk}|;8H$c)ODRaxN z8Ye-wknJR?raQ41l@BAd7hzOMt52r`jH=pkG=|2}sU)Zl)fy>`j(~4$ozjn>hE_1{ zyfLM{Lfuy0-_oI zIiE|K7%~;jP~%+v2OnWrH22a7(<)DxW&!a-9p(r#oY-~3LnGkSmxZ1%s|K#Aft5|H zcrw%)T&+{6bG8;5QKO*|wJv%#y?WbfM>eBj?xX_#K}90dhW=H-3qn4onZl0kv%133 z1mHkzq8JA_Q63{HveU>u*|o=j5r0Aqq>e+A#6|N5fGq)hb~{?Ny%hpiXSa!>$<=;E zz~bsjn&aw4EA;SQrS4N~pJEC$e7|D-z(UiRs3qlo#0?)*#$0Ee1Lk=hH$Ds|b^dOb zqm{is+uh`m(ar16542{tMo(;%?v?+z%RC1)3p!U1Y=oz%k(a0qcNF)#=ln9OuXyAF e&x1}qFG9`nN!K*(9WuXU_G^Rf6TtWgsJ{axyq0tT literal 0 HcmV?d00001 diff --git a/Finished Code/python/src/recitation/election/data/conventions.csv b/Finished Code/python/src/recitation/election/data/conventions.csv new file mode 100644 index 0000000..bc9e629 --- /dev/null +++ b/Finished Code/python/src/recitation/election/data/conventions.csv @@ -0,0 +1,51 @@ +Alabama,33.86695773,66.13304227 +Alaska,52.77777778,47.22222222 +Arizona,48.78267555,51.21732445 +Arkansas,42.51223929,57.48776071 +California,67.46493113,32.53506887 +Colorado,54.65047528,45.34952472 +Connecticut,59.11145551,40.88854449 +Delaware,59.07963005,40.92036995 +District of Columbia,64.05570061,35.94429939 +Florida,53.86044044,46.13955956 +Georgia,46.23483446,53.76516554 +Hawaii,69.88979271,30.11020729 +Idaho,39.15450428,60.84549572 +Illinois,62.38961734,37.61038266 +Indiana,43.160299,56.839701 +Iowa,51.85149188,48.14850812 +Kansas,48.11919556,51.88080444 +Kentucky,47.62026612,52.37973388 +Louisiana,40.84012539,59.15987461 +Maine,57.60145366,42.39854634 +Maryland,66.76285414,33.23714586 +Massachusetts,66.81608523,33.18391477 +Michigan,52.99960789,47.00039211 +Minnesota,58.12451744,41.87548256 +Mississippi,34.75420037,65.24579963 +Missouri,54.90702479,45.09297521 +Montana,46.72523962,53.27476038 +Nebraska,46.55953251,53.44046749 +Nevada,49.9762121,50.0237879 +New Hampshire,60.4576449,39.5423551 +New Jersey,59.03060204,40.96939796 +New Mexico,55.21274175,44.78725825 +New York,62.60577569,37.39422431 +North Carolina,49.8196006,50.1803994 +North Dakota,33.87146371,66.12853629 +Ohio,51.97145123,48.02854877 +Oklahoma,36.63899338,63.36100662 +Oregon,57.6187378,42.3812622 +Pennsylvania,53.1753379,46.8246621 +Rhode Island,55.83333333,44.16666667 +South Carolina,46.51853725,53.48146275 +South Dakota,41.58382477,58.41617523 +Tennessee,41.69142541,58.30857459 +Texas,42.34618978,57.65381022 +Utah,41.86378036,58.13621964 +Vermont,86.35511323,13.64488677 +Virginia,57.66956409,42.33043591 +Washington,59.31714516,40.68285484 +West Virginia,45.68239915,54.31760085 +Wisconsin,57.32167832,42.67832168 +Wyoming,35.02788845,64.97211155 \ No newline at end of file diff --git a/Finished Code/python/src/recitation/election/data/debates.csv b/Finished Code/python/src/recitation/election/data/debates.csv new file mode 100644 index 0000000..b4de60c --- /dev/null +++ b/Finished Code/python/src/recitation/election/data/debates.csv @@ -0,0 +1,51 @@ +Alabama,25.57864282,74.42135718 +Alaska,51.74333819,48.25666181 +Arizona,54.07366071,45.92633929 +Arkansas,39.49400799,60.50599201 +California,62.18633209,37.81366791 +Colorado,56.95519282,43.04480718 +Connecticut,62.58445946,37.41554054 +Delaware,72.243404,27.756596 +District of Columbia,86.39077906,13.60922094 +Florida,49.13971934,50.86028066 +Georgia,39.77695167,60.22304833 +Hawaii,78.54251012,21.45748988 +Idaho,38.9151281,61.0848719 +Illinois,64.01312266,35.98687734 +Indiana,51.90771961,48.09228039 +Iowa,56.57914256,43.42085744 +Kansas,55.97600369,44.02399631 +Kentucky,49.86316366,50.13683634 +Louisiana,40.59007018,59.40992982 +Maine,62.83742465,37.16257535 +Maryland,67.8948832,32.1051168 +Massachusetts,68.90841931,31.09158069 +Michigan,56.18987871,43.81012129 +Minnesota,57.14070276,42.85929724 +Mississippi,34.57598179,65.42401821 +Missouri,56.47835657,43.52164343 +Montana,45.00144886,54.99855114 +Nebraska,46.55953251,53.44046749 +Nevada,51.67688895,48.32311105 +New Hampshire,60.88105145,39.11894855 +New Jersey,56.10281254,43.89718746 +New Mexico,61.50711424,38.49288576 +New York,57.9081976,42.0918024 +North Carolina,49.3203998,50.6796002 +North Dakota,33.37239965,66.62760035 +Ohio,49.8957439,50.1042561 +Oklahoma,42.24100248,57.75899752 +Oregon,60.99816369,39.00183631 +Pennsylvania,53.47880522,46.52119478 +Rhode Island,61.11414528,38.88585472 +South Carolina,42.24614077,57.75385923 +South Dakota,49.18389554,50.81610446 +Tennessee,42.87445164,57.12554836 +Texas,45.57180257,54.42819743 +Utah,45.54707379,54.45292621 +Vermont,61.9060889,38.0939111 +Virginia,58.74475856,41.25524144 +Washington,62.40545651,37.59454349 +West Virginia,33.4566379,66.5433621 +Wisconsin,60.81730769,39.18269231 +Wyoming,34.89883052,65.10116948 \ No newline at end of file diff --git a/Finished Code/python/src/recitation/election/data/earlyPolls.csv b/Finished Code/python/src/recitation/election/data/earlyPolls.csv new file mode 100644 index 0000000..3f0ca5a --- /dev/null +++ b/Finished Code/python/src/recitation/election/data/earlyPolls.csv @@ -0,0 +1,51 @@ +Alabama,32,68 +Alaska,47.21627409,52.78372591 +Arizona,50.47318612,49.52681388 +Arkansas,43.37349398,56.62650602 +California,65.7223796,34.2776204 +Colorado,49.71098266,50.28901734 +Connecticut,54.54545455,45.45454545 +Delaware,56.75675676,43.24324324 +District of Columbia,64.05570061,35.94429939 +Florida,52.44366704,47.55633296 +Georgia,49.53703704,50.46296296 +Hawaii,69.88979271,30.11020729 +Idaho,39.50617284,60.49382716 +Illinois,61.11111111,38.88888889 +Indiana,45.12195122,54.87804878 +Iowa,51.61290323,48.38709677 +Kansas,43.90243902,56.09756098 +Kentucky,45.71890145,54.28109855 +Louisiana,40.90909091,59.09090909 +Maine,55.84415584,44.15584416 +Maryland,69.25925926,30.74074074 +Massachusetts,67.24137931,32.75862069 +Michigan,55.16431925,44.83568075 +Minnesota,55.48780488,44.51219512 +Mississippi,48.31460674,51.68539326 +Missouri,48.36065574,51.63934426 +Montana,36.85503686,63.14496314 +Nebraska,52.02799427,47.97200573 +Nevada,48.23529412,51.76470588 +New Hampshire,54.25894378,45.74105622 +New Jersey,58.62068966,41.37931034 +New Mexico,55.40540541,44.59459459 +New York,61.48373984,38.51626016 +North Carolina,50.45558087,49.54441913 +North Dakota,33.87146371,66.12853629 +Ohio,51.0851419,48.9148581 +Oklahoma,36.84210526,63.15789474 +Oregon,52.79503106,47.20496894 +Pennsylvania,53.22982276,46.77017724 +Rhode Island,55.83333333,44.16666667 +South Carolina,47.70114943,52.29885057 +South Dakota,41.58382477,58.41617523 +Tennessee,44.30379747,55.69620253 +Texas,48.35164835,51.64835165 +Utah,47.18309859,52.81690141 +Vermont,61.9047619,38.0952381 +Virginia,57.22713864,42.77286136 +Washington,56.97674419,43.02325581 +West Virginia,31.39534884,68.60465116 +Wisconsin,56.27240143,43.72759857 +Wyoming,35.02788845,64.97211155 \ No newline at end of file diff --git a/Finished Code/python/src/recitation/election/data/electoralVotes.csv b/Finished Code/python/src/recitation/election/data/electoralVotes.csv new file mode 100644 index 0000000..c4bc236 --- /dev/null +++ b/Finished Code/python/src/recitation/election/data/electoralVotes.csv @@ -0,0 +1,51 @@ +Alabama,9 +Alaska,3 +Arizona,11 +Arkansas,6 +California,55 +Colorado,9 +Connecticut,7 +Delaware,3 +District of Columbia,3 +Florida,29 +Georgia,16 +Hawaii,4 +Idaho,4 +Illinois,20 +Indiana,11 +Iowa,6 +Kansas,6 +Kentucky,8 +Louisiana,8 +Maine,4 +Maryland,10 +Massachusetts,11 +Michigan,16 +Minnesota,10 +Mississippi,6 +Missouri,10 +Montana,3 +Nebraska,5 +Nevada,6 +New Hampshire,4 +New Jersey,14 +New Mexico,5 +New York,29 +North Carolina,15 +North Dakota,3 +Ohio,18 +Oklahoma,7 +Oregon,7 +Pennsylvania,20 +Rhode Island,4 +South Carolina,9 +South Dakota,3 +Tennessee,11 +Texas,38 +Utah,6 +Vermont,3 +Virginia,13 +Washington,12 +West Virginia,5 +Wisconsin,10 +Wyoming,3 \ No newline at end of file diff --git a/Finished Code/python/src/recitation/election/election_io.py b/Finished Code/python/src/recitation/election/election_io.py new file mode 100644 index 0000000..b115073 --- /dev/null +++ b/Finished Code/python/src/recitation/election/election_io.py @@ -0,0 +1,38 @@ +import csv # csv is a library within python that lets you read csv files + + +def process_electoral_votes(file_path): + """ + takes in a file path woth the csv file with the first col as the state and the second col with how many votes tayt state gets. + This will return a dictionary mapping states to how many votes they get. + """ + + result = dict() + with open(file_path, 'r') as f: + reader = csv.reader(f) + for row in reader: + state = row[0] + votes = row[1] + result[state] = votes + print(row) + + return result + + + +def process_poll_results(file_path): + """ + Takes in a file path with the csv file woth first col = state, second col = canodate 1 results, third col = canidate 2 results, returns a dictionary mapping states to canidate results. + dictionary key = state, value = c1 results. + """ + + result = dict() + with open(file_path, 'r') as f: + reader = csv.reader(f) + for row in reader: + print(row) + state = row[0] + c1_results = row[1] + result[state] = c1_results + + return result diff --git a/Finished Code/python/src/recitation/election/main.py b/Finished Code/python/src/recitation/election/main.py new file mode 100644 index 0000000..b1d0052 --- /dev/null +++ b/Finished Code/python/src/recitation/election/main.py @@ -0,0 +1,22 @@ +import random # for generating random numbers +from election_io import * # for reading from files + +def main() : + print("Let's simulate an election!") # reading csv files! + + electoral_votes_file_path = "data/electoralVotes.csv" + electoral_votes = process_electoral_votes(electoral_votes_file_path) + + # print("electoral_votes", electoral_votes) + + print("electoral_votes", electoral_votes) + + + + + + + +if __name__ == "__main__": + main() + diff --git a/Finished Code/python/src/recitation/primes/__pycache__/main.cpython-313.pyc b/Finished Code/python/src/recitation/primes/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6335a413a73b2c8ff2617386fcc76d05ebd1c07e GIT binary patch literal 5183 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 literal 0 HcmV?d00001 diff --git a/Finished Code/python/src/recitation/primes/__pycache__/main.cpython-314.pyc b/Finished Code/python/src/recitation/primes/__pycache__/main.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbdb4ae68c381ba26f6c222edf55b4521673de9a GIT binary patch literal 6076 zcmcgwTW=f36`tiTC2B=6y5BD=%aKi4rY%`k6*UN8SQ20>Q6yTSik23!B3I(Z6L9UqmbG2>Ay8?A=*k!j**&Jn|UG6v&! z)DgqcMEqZ$ z#s`?f_@MI#j4j@0tfMfmp9v7ZBjD)ctZ}d(7PN8Y-WtzKxfVhSyI0x$^lp3M_XBJ< zy;o~)m9y!^1vtO63~s5Hwe38w&2#nI=Zs!jFQ-kf;(+s6y#mf@GH?^@qY3R}YPh?! za9V1S?QK_}$X^1x;_bWgmx2Ys&+ATl#x*%E3A3^ik(D`LvV1Zs2`aYf!n`UN36m8y zNlty7Cdo!alNV$$7NY$jd`Hq?NaB)^WPSa!$r3@A!U-j!`;tw%EG%Lv5wX) zSjGGxJQ#dWmoz=7C)B7Md{>c%;Dn^$kfdKS5^7MrYD5!Ca9m5wX<|GM2Rxh5E`()C zF<@=I_hj$s_wWp%Hxe9?6F>pHE&ece{$~nxf`R)udh`f zNxehgJaWJ6Q8;sC@N;j5A6n&xw~C0XX6f>3asA`U_O;3ri^UtRvZa#rk>!qb%d(R3 zoL+bJZ##*rVF$KM!U$|Rpu>}(05}3diUi2CW8fM%3bZwo2`0+;nIQC7#qS8_z?=lL zfJ8`lW3Hc&6OIn@fc+LnX^0$VktP}Qn(}}(Su{|NS`mk~twxZk*F=%~ygtpdlp zLm^R75^#Z1D5SMO(>w6fTcJvk??@HXxQ*5Avs?JMJM^&n-g(-hRlyLtHF(mJ-5R&^ zDg32dBLi^x5jSql=JR>vhRr&BfVb03cXkSVbmx(Z5J3EV9GG_O9od&XoN_W!4r3j* zIN-=(s05=qr1W}1VOE@-e<`w6Nn9n1J=f+pJoTA| zo)u4T#?=eXRM)&TwahHH-(zouQe)tko~osuB{9w13V(EQk=bZIygc#Q=%Q!E)v(PH zPZPZ2Zp?5E1ryA97y1aQv2&6x_~PD$e&l7fT6j%6j1`b7;&o^ZC_@k~$CTgZ=)Z!hFpL(A+@LDA^9K;JK!Dx?ZOxQF6+C9zQSgES z42C`Q!e z^vjw7cZ2t2GM98jfzGVi9m26#(K|T{g3au{eyuudTsOnF5C7i#sdxFzXWh$}@Ay_~ zz3XLNi_DW!_is)wo%v|ctg7EGCZ1#4ZsIO4Twc!3{tqaw)u8J2P#t7ySD-%+&J768 zP~E<;g^#=LU{f6f!h8N-{a(Ez$%K3LdH*!M{hLGONN`Lf3&| z&xYdjF++x}>skl&?2Z#iST(GuW&aWcaM45M#-%`dB7OPJg+HJT7fmD{Wrp)=Lj>ww!#_y3%s?!!dO9<6Hdq z#S~Ny0FmrOsd5L$lmcJdZJ!0$_Ok_kxBuu9EW{$tibZJ1wt&QH7-ncdqKJ49R9uIV zx|izw9ce_Ufa)RlaPp7*7K(ok)5n*QzxDm~ecEZE2Eu8s+$7LldBajGZP19J_-Zd>p_Vg96kL?oVa?>=cXWG+L6y z0D@;Mez6M!6ku-=Ai@!gb;*iwB`O2Y6Js$OCxm9CgOoI0i6$UmVR9MI0aWSNeKPDXn9(rJ; ze#JagxB`I3KkxW3dEQH-w~?VwTCqB!vPO zxLU!>Fo)96X><;%&ODvP1VzJ&de!?N08F(aOr5#5K+?W1#04oK%o!DB2xfiF&0+J`h#!-|@S z2!f4&Q+GJE;_1t{`kqu&rOrdRu059h+LI66={y^^Me8T-+P}M7zH+yu#dWtpsX0dM z+6-4it;}?VLin{Q6!Ml>Bm^&$etWV~QJNUgjZs%d74aPfvhq;q0ilyvUqoDQ#uJhG znDmy`4};K_^dYFWScYN#K}x?NrT^kOn4fID%?J$lbclh^B2T*@(|g(l9QyPad{ua literal 0 HcmV?d00001 diff --git a/Finished Code/python/src/recitation/primes/main.py b/Finished Code/python/src/recitation/primes/main.py new file mode 100644 index 0000000..4b2c9b9 --- /dev/null +++ b/Finished Code/python/src/recitation/primes/main.py @@ -0,0 +1,200 @@ +import math + +import time + +def main(): + print("Prime finding.") + + n = 10 + + prime_booleans = trivial_prime_finder(n) + + print(prime_booleans) + + prime_booleans = sieve_of_eratosthenes(n) + + print(prime_booleans) + + prime_list = list_primes(n) + + print("The primes up to", n, "are", prime_list) + + # timing trivial_prime_finder + + n = 10000000 + + start = time.time() # START + trivial_prime_finder(n) + elapsed_trivial = time.time() - start # STOP + print(f"trivial_prime_finder took {elapsed_trivial:.6f} seconds.") + + #timing sieve + start = time.time() + sieve_of_eratosthenes(n) + elapsed_sieve = time.time() - start # STOP + print(f"sieve_of_eratosthenes took {elapsed_sieve:.6f} seconds.") + + # print the speedup + if elapsed_sieve > 0: + speedup = elapsed_trivial/elapsed_sieve + print(f"Speedup: {speedup:.2f} times faster.") + + +""" +Pseudocode below. + +TrivialPrimeFinder(n) + primeBooleans ← array of n+1 false boolean variables + for every integer p from 2 to n + if IsPrime(p) is true + primeBooleans[p] ← true + return primeBooleans + +IsPrime(p) + if p < 2 + return false + for every integer k between 2 and √p + if k is a divisor of p + return false + return true + +SieveOfEratosthenes(n) + primeBooleans ← array of n+1 true boolean variables + primeBooleans[0] ← false + primeBooleans[1] ← false + for every integer p between 2 and √n + if primeBooleans[p] = true + primeBooleans ← CrossOffMultiples(primeBooleans, p) + return primeBooleans + +CrossOffMultiples(primeBooleans, p) + n ← length(primeBooleans) - 1 + for every multiple k of p (from 2p to n) + primeBooleans[k] ← false + return primeBooleans +""" + +def trivial_prime_finder(n: int) -> list[bool]: + """ + Returns a list of boolean variables storing the primality of each nonnegative integer up to and including n. + Parameters: + - n (int): an integer + Returns: + list[bool]: a list of boolean variables storing the primality of each nonnegative integer up to and including n. + """ + + if n < 0: + raise ValueError("n must be nonnegative.") + + # initialize a bunch of values to False + prime_booleans = [False] * (n+1) + + # range over all integers from 2 to n, checking if each one is prime + for p in range(2, n+1): + prime_booleans[p] = is_prime(p) + + return prime_booleans + +def is_prime(p: int) -> bool: + """ + Test if p is prime. + Parameters: + - p (int): an integer + Returns: + bool: True if p is prime and False otherwise. + """ + + if p < 2: + return False + + # range over all possible divisors between 2 and sqrt(p), and if we find one that is a divisor of p, it can't be prime + for k in range(2, int(math.sqrt(p)+1)): + # if k is a divisor of p, return false + if p % k == 0: + return False + + # if we make it here, we never found a divisor of p, which must be prime + return True + +def sieve_of_eratosthenes(n: int) -> list[bool]: + """ + Returns a list of boolean variables storing the primality of each nonnegative integer up to and including n, + implementing the "sieve of Eratosthenes" algorithm. + Parameters: + - n (int): an integer + Returns: + list: a list of boolean variables storing the primality of each nonnegative integer up to and including n. + """ + + if n < 0: + raise ValueError("n must be nonnegative.") + + prime_booleans = [True]*(n+1) + + # we know that 0 and 1 are not prime + prime_booleans[0] = False + prime_booleans[1] = False + + # range over every p between 2 and sqrt(n) and cross off its multiples + for p in range(2, int(math.sqrt(n) + 1)): + if prime_booleans[p] == True: + # we know that p is prime, so cross off its multiples (i.e., set its multiples to false) + prime_booleans = cross_off_multiples(prime_booleans, p) + + return prime_booleans + +def cross_off_multiples(prime_booleans: list[bool], p:int) -> list[bool]: + """ + Returns an updated list in which all variables in the list whose indices are multiples of p (greater than p) have + been set to false. + Parameters: + - prime_booleans (list): a list of boolean variables storing the primality of each nonnegative integer + - p (int): an integer + Returns: + list[bool]: a list of boolean variables storing the primality of each nonnegative integer up to and including n with + multiples of p (greater than p) set to false. + """ + + # we know that len(prime_booleans) = n + 1 + # n = len(prime_booleans) - 1 + + if p <= 0: + raise ValueError("p should be positive.") + + if len(prime_booleans) == 0: + raise ValueError("empty prime_booleans list.") + + n = len(prime_booleans) - 1 + + for k in range(2*p, n+1, p): + prime_booleans[k] = False + + return prime_booleans + +def list_primes(n: int) -> list[int]: + """ + List all prime numbers up to and (possibly) including n. + Parameters: + - n (int): an integer + Returns: + list[int]: a list containing all prime numbers up to and (possibly) including n. + """ + + if n < 0: + raise ValueError("n should be nonnegative.") + + prime_list = [] + + # first, use sieve of Eratosthenes + prime_booleans = sieve_of_eratosthenes(n) + + # range over this list of booleans, and if we find something that's prime, add it to prime_list + for p in range(0, len(prime_booleans)): + if prime_booleans[p] == True: + # add it to list of primes! + prime_list.append(p) + + return prime_list + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Finished Code/python/src/recitation/recitation1starter.py b/Finished Code/python/src/recitation/recitation1starter.py new file mode 100644 index 0000000..2ee0dfe --- /dev/null +++ b/Finished Code/python/src/recitation/recitation1starter.py @@ -0,0 +1,95 @@ +import math +from primes.main import sieve_of_eratosthenes +import matplotlib.pyplot as plt + + +def prime_count_array(n: int): + #TODO Implement this function + """ + We will return a list of how many primes we've seen so far at a given index. + input: n -> int + output: list of how many primes we've seen so far at a given index. + """ + prime_list = sieve_of_eratosthenes(n) + result = [0] * (n + 1) + counter = 0 + for i in range(len(prime_list)): + is_prime = prime_list[i] + if is_prime: + counter = counter + 1 + result[i] = counter + return result + + +def prime_count_array_plotting(): + N = 200000 + pi = prime_count_array(N) + # Sample points to keep plotting light + step = 100 + xs = list(range(2, N + 1, step)) + ys = [pi[x] for x in xs] + ys_approx = [x / math.log(x) for x in xs] # n/log n approximation + # Plot + plt.figure(figsize=(9, 6)) + plt.plot(xs, ys, label=r"$\pi(n)$ (prime count)") + plt.plot(xs, ys_approx, linestyle="--", label=r"$n/\log n$ (approximation)") + plt.title("Prime Counting Function $\\pi(n)$ vs. $n$ (with $n/\\log n$ approximation)") + plt.xlabel("n") + plt.ylabel(r"$\pi(n)$") + plt.legend() + plt.tight_layout() + plt.show() + +def ulam_coords(n: int): + coords = [(0, 0)] * n + x = y = 0 + k = 1 + step_len = 1 + + def write_and_step(dx, dy, steps, k, x, y): + for _ in range(steps): + if k > n: + break + coords[k - 1] = (x, y) + x += dx + y += dy + k += 1 + return k, x, y + while k <= n: + # right, up + k, x, y = write_and_step(1, 0, step_len, k, x, y) + k, x, y = write_and_step(0, 1, step_len, k, x, y) + step_len += 1 + # left, down + k, x, y = write_and_step(-1, 0, step_len, k, x, y) + k, x, y = write_and_step(0, -1, step_len, k, x, y) + step_len += 1 + return coords + +def plot_ulam(n: int = 20000, point_size: float = 2.0): + is_prime = sieve_of_eratosthenes(n) + coords = ulam_coords(n) + xs = [] + ys = [] + for k in range(2, n + 1): # start at 2 (first prime) + if is_prime[k]: + x, y = coords[k - 1] + xs.append(x) + ys.append(y) + plt.figure(figsize=(8, 8)) + plt.scatter(xs, ys, s=point_size) + plt.gca().set_aspect('equal', adjustable='box') + plt.axis('off') + plt.title(f"Ulam Spiral of Primes up to {n}") + plt.show() + plt.close() + + +def main(): + prime_count_array_plotting() + # plot_ulam(n=30000, point_size=1.8) + + + +if __name__ == "__main__": + main() \ No newline at end of file