diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7a60579dc6e..a9d07615e2c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -63,3 +63,9 @@ repos: rev: "0.26" hooks: - id: validate-pyproject + + - repo: https://github.com/15r10nk/matchify + rev: v0.2.0 + hooks: + - id: matchify + exclude: ^data_structures/linked_list/doubly_linked_list\.py$ diff --git a/DIRECTORY.md b/DIRECTORY.md index 0b64fc4b6923..dc8907fa8919 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1339,6 +1339,8 @@ * [Sol1](project_euler/problem_107/sol1.py) * Problem 109 * [Sol1](project_euler/problem_109/sol1.py) + * Problem 111 + * [Sol1](project_euler/problem_111/sol1.py) * Problem 112 * [Sol1](project_euler/problem_112/sol1.py) * Problem 113 @@ -1361,6 +1363,8 @@ * [Sol1](project_euler/problem_122/sol1.py) * Problem 123 * [Sol1](project_euler/problem_123/sol1.py) + * Problem 124 + * [Sol1](project_euler/problem_124/sol1.py) * Problem 125 * [Sol1](project_euler/problem_125/sol1.py) * Problem 129 @@ -1371,6 +1375,12 @@ * [Sol1](project_euler/problem_135/sol1.py) * Problem 136 * [Sol1](project_euler/problem_136/sol1.py) + * Problem 137 + * [Sol1](project_euler/problem_137/sol1.py) + * Problem 138 + * [Sol1](project_euler/problem_138/sol1.py) + * Problem 142 + * [Sol1](project_euler/problem_142/sol1.py) * Problem 144 * [Sol1](project_euler/problem_144/sol1.py) * Problem 145 diff --git a/ciphers/autokey.py b/ciphers/autokey.py index 7751a32d7546..0b269dc0adad 100644 --- a/ciphers/autokey.py +++ b/ciphers/autokey.py @@ -139,12 +139,13 @@ def decrypt(ciphertext: str, key: str) -> str: doctest.testmod() operation = int(input("Type 1 to encrypt or 2 to decrypt:")) - if operation == 1: - plaintext = input("Typeplaintext to be encrypted:\n") - key = input("Type the key:\n") - print(encrypt(plaintext, key)) - elif operation == 2: - ciphertext = input("Type the ciphertext to be decrypted:\n") - key = input("Type the key:\n") - print(decrypt(ciphertext, key)) + match operation: + case 1: + plaintext = input("Typeplaintext to be encrypted:\n") + key = input("Type the key:\n") + print(encrypt(plaintext, key)) + case 2: + ciphertext = input("Type the ciphertext to be decrypted:\n") + key = input("Type the key:\n") + print(decrypt(ciphertext, key)) decrypt("jsqqs avvwo", "coffee") diff --git a/ciphers/hill_cipher.py b/ciphers/hill_cipher.py index c690d29bd113..a6038e576c14 100644 --- a/ciphers/hill_cipher.py +++ b/ciphers/hill_cipher.py @@ -203,14 +203,15 @@ def main() -> None: print("Would you like to encrypt or decrypt some text? (1 or 2)") option = input("\n1. Encrypt\n2. Decrypt\n") - if option == "1": - text_e = input("What text would you like to encrypt?: ") - print("Your encrypted text is:") - print(hc.encrypt(text_e)) - elif option == "2": - text_d = input("What text would you like to decrypt?: ") - print("Your decrypted text is:") - print(hc.decrypt(text_d)) + match option: + case "1": + text_e = input("What text would you like to encrypt?: ") + print("Your encrypted text is:") + print(hc.encrypt(text_e)) + case "2": + text_d = input("What text would you like to decrypt?: ") + print("Your decrypted text is:") + print(hc.decrypt(text_d)) if __name__ == "__main__": diff --git a/ciphers/mono_alphabetic_ciphers.py b/ciphers/mono_alphabetic_ciphers.py index 46013f4936bc..f9594ca8af5f 100644 --- a/ciphers/mono_alphabetic_ciphers.py +++ b/ciphers/mono_alphabetic_ciphers.py @@ -49,10 +49,11 @@ def main() -> None: key = "QWERTYUIOPASDFGHJKLZXCVBNM" mode = "decrypt" # set to 'encrypt' or 'decrypt' - if mode == "encrypt": - translated = encrypt_message(key, message) - elif mode == "decrypt": - translated = decrypt_message(key, message) + match mode: + case "encrypt": + translated = encrypt_message(key, message) + case "decrypt": + translated = decrypt_message(key, message) print(f"Using the key {key}, the {mode}ed message is: {translated}") diff --git a/ciphers/rsa_cipher.py b/ciphers/rsa_cipher.py index ac9782a49fff..d974e0c8a176 100644 --- a/ciphers/rsa_cipher.py +++ b/ciphers/rsa_cipher.py @@ -121,28 +121,31 @@ def main() -> None: elif response.lower().startswith("d"): mode = "decrypt" - if mode == "encrypt": - if not os.path.exists("rsa_pubkey.txt"): - rkg.make_key_files("rsa", 1024) - - message = input("\nEnter message: ") - pubkey_filename = "rsa_pubkey.txt" - print(f"Encrypting and writing to {filename}...") - encrypted_text = encrypt_and_write_to_file(filename, pubkey_filename, message) - - print("\nEncrypted text:") - print(encrypted_text) - - elif mode == "decrypt": - privkey_filename = "rsa_privkey.txt" - print(f"Reading from {filename} and decrypting...") - decrypted_text = read_from_file_and_decrypt(filename, privkey_filename) - print("writing decryption to rsa_decryption.txt...") - with open("rsa_decryption.txt", "w") as dec: - dec.write(decrypted_text) - - print("\nDecryption:") - print(decrypted_text) + match mode: + case "encrypt": + if not os.path.exists("rsa_pubkey.txt"): + rkg.make_key_files("rsa", 1024) + + message = input("\nEnter message: ") + pubkey_filename = "rsa_pubkey.txt" + print(f"Encrypting and writing to {filename}...") + encrypted_text = encrypt_and_write_to_file( + filename, pubkey_filename, message + ) + + print("\nEncrypted text:") + print(encrypted_text) + + case "decrypt": + privkey_filename = "rsa_privkey.txt" + print(f"Reading from {filename} and decrypting...") + decrypted_text = read_from_file_and_decrypt(filename, privkey_filename) + print("writing decryption to rsa_decryption.txt...") + with open("rsa_decryption.txt", "w") as dec: + dec.write(decrypted_text) + + print("\nDecryption:") + print(decrypted_text) if __name__ == "__main__": diff --git a/ciphers/vigenere_cipher.py b/ciphers/vigenere_cipher.py index e76161351fb1..37b96ea14a46 100644 --- a/ciphers/vigenere_cipher.py +++ b/ciphers/vigenere_cipher.py @@ -41,10 +41,11 @@ def translate_message(key: str, message: str, mode: str) -> str: for symbol in message: num = LETTERS.find(symbol.upper()) if num != -1: - if mode == "encrypt": - num += LETTERS.find(key[key_index]) - elif mode == "decrypt": - num -= LETTERS.find(key[key_index]) + match mode: + case "encrypt": + num += LETTERS.find(key[key_index]) + case "decrypt": + num -= LETTERS.find(key[key_index]) num %= len(LETTERS) diff --git a/computer_vision/flip_augmentation.py b/computer_vision/flip_augmentation.py index 7301424824df..1c4fad847471 100644 --- a/computer_vision/flip_augmentation.py +++ b/computer_vision/flip_augmentation.py @@ -96,16 +96,17 @@ def update_image_and_anno( path_list.append(path) img_annos = anno_list[idx] img = cv2.imread(path) - if flip_type == 1: - new_img = cv2.flip(img, flip_type) - for bbox in img_annos: - x_center_new = 1 - bbox[1] - new_annos.append([bbox[0], x_center_new, bbox[2], bbox[3], bbox[4]]) - elif flip_type == 0: - new_img = cv2.flip(img, flip_type) - for bbox in img_annos: - y_center_new = 1 - bbox[2] - new_annos.append([bbox[0], bbox[1], y_center_new, bbox[3], bbox[4]]) + match flip_type: + case 1: + new_img = cv2.flip(img, flip_type) + for bbox in img_annos: + x_center_new = 1 - bbox[1] + new_annos.append([bbox[0], x_center_new, bbox[2], bbox[3], bbox[4]]) + case 0: + new_img = cv2.flip(img, flip_type) + for bbox in img_annos: + y_center_new = 1 - bbox[2] + new_annos.append([bbox[0], bbox[1], y_center_new, bbox[3], bbox[4]]) new_annos_lists.append(new_annos) new_imgs_list.append(new_img) return new_imgs_list, new_annos_lists, path_list diff --git a/computer_vision/mosaic_augmentation.py b/computer_vision/mosaic_augmentation.py index d881347121ea..753b8bf012ef 100644 --- a/computer_vision/mosaic_augmentation.py +++ b/computer_vision/mosaic_augmentation.py @@ -117,46 +117,48 @@ def update_image_and_anno( path_list.append(path) img_annos = all_annos[index] img = cv2.imread(path) - if i == 0: # top-left - img = cv2.resize(img, (divid_point_x, divid_point_y)) - output_img[:divid_point_y, :divid_point_x, :] = img - for bbox in img_annos: - xmin = bbox[1] * scale_x - ymin = bbox[2] * scale_y - xmax = bbox[3] * scale_x - ymax = bbox[4] * scale_y - new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) - elif i == 1: # top-right - img = cv2.resize(img, (output_size[1] - divid_point_x, divid_point_y)) - output_img[:divid_point_y, divid_point_x : output_size[1], :] = img - for bbox in img_annos: - xmin = scale_x + bbox[1] * (1 - scale_x) - ymin = bbox[2] * scale_y - xmax = scale_x + bbox[3] * (1 - scale_x) - ymax = bbox[4] * scale_y - new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) - elif i == 2: # bottom-left - img = cv2.resize(img, (divid_point_x, output_size[0] - divid_point_y)) - output_img[divid_point_y : output_size[0], :divid_point_x, :] = img - for bbox in img_annos: - xmin = bbox[1] * scale_x - ymin = scale_y + bbox[2] * (1 - scale_y) - xmax = bbox[3] * scale_x - ymax = scale_y + bbox[4] * (1 - scale_y) - new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) - else: # bottom-right - img = cv2.resize( - img, (output_size[1] - divid_point_x, output_size[0] - divid_point_y) - ) - output_img[ - divid_point_y : output_size[0], divid_point_x : output_size[1], : - ] = img - for bbox in img_annos: - xmin = scale_x + bbox[1] * (1 - scale_x) - ymin = scale_y + bbox[2] * (1 - scale_y) - xmax = scale_x + bbox[3] * (1 - scale_x) - ymax = scale_y + bbox[4] * (1 - scale_y) - new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) + match i: + case 0: # top-left + img = cv2.resize(img, (divid_point_x, divid_point_y)) + output_img[:divid_point_y, :divid_point_x, :] = img + for bbox in img_annos: + xmin = bbox[1] * scale_x + ymin = bbox[2] * scale_y + xmax = bbox[3] * scale_x + ymax = bbox[4] * scale_y + new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) + case 1: # top-right + img = cv2.resize(img, (output_size[1] - divid_point_x, divid_point_y)) + output_img[:divid_point_y, divid_point_x : output_size[1], :] = img + for bbox in img_annos: + xmin = scale_x + bbox[1] * (1 - scale_x) + ymin = bbox[2] * scale_y + xmax = scale_x + bbox[3] * (1 - scale_x) + ymax = bbox[4] * scale_y + new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) + case 2: # bottom-left + img = cv2.resize(img, (divid_point_x, output_size[0] - divid_point_y)) + output_img[divid_point_y : output_size[0], :divid_point_x, :] = img + for bbox in img_annos: + xmin = bbox[1] * scale_x + ymin = scale_y + bbox[2] * (1 - scale_y) + xmax = bbox[3] * scale_x + ymax = scale_y + bbox[4] * (1 - scale_y) + new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) + case _: # bottom-right + img = cv2.resize( + img, + (output_size[1] - divid_point_x, output_size[0] - divid_point_y), + ) + output_img[ + divid_point_y : output_size[0], divid_point_x : output_size[1], : + ] = img + for bbox in img_annos: + xmin = scale_x + bbox[1] * (1 - scale_x) + ymin = scale_y + bbox[2] * (1 - scale_y) + xmax = scale_x + bbox[3] * (1 - scale_x) + ymax = scale_y + bbox[4] * (1 - scale_y) + new_anno.append([bbox[0], xmin, ymin, xmax, ymax]) # Remove bounding box small than scale of filter if filter_scale > 0: diff --git a/conversions/decimal_to_any.py b/conversions/decimal_to_any.py index c9c2e9a5fb71..b257761eff40 100644 --- a/conversions/decimal_to_any.py +++ b/conversions/decimal_to_any.py @@ -81,11 +81,12 @@ def decimal_to_any(num: int, base: int) -> str: new_value += actual_value div = num // base num = div - if div == 0: - return str(new_value[::-1]) - elif div == 1: - new_value += str(div) - return str(new_value[::-1]) + match div: + case 0: + return str(new_value[::-1]) + case 1: + new_value += str(div) + return str(new_value[::-1]) return new_value[::-1] diff --git a/data_structures/binary_tree/avl_tree.py b/data_structures/binary_tree/avl_tree.py index 8558305eefe4..bb15afd331a8 100644 --- a/data_structures/binary_tree/avl_tree.py +++ b/data_structures/binary_tree/avl_tree.py @@ -225,18 +225,19 @@ def del_node(root: MyNode, data: Any) -> MyNode | None: left_child = root.get_left() right_child = root.get_right() - if get_height(right_child) - get_height(left_child) == 2: - assert right_child is not None - if get_height(right_child.get_right()) > get_height(right_child.get_left()): - root = left_rotation(root) - else: - root = rl_rotation(root) - elif get_height(right_child) - get_height(left_child) == -2: - assert left_child is not None - if get_height(left_child.get_left()) > get_height(left_child.get_right()): - root = right_rotation(root) - else: - root = lr_rotation(root) + match get_height(right_child) - get_height(left_child): + case 2: + assert right_child is not None + if get_height(right_child.get_right()) > get_height(right_child.get_left()): + root = left_rotation(root) + else: + root = rl_rotation(root) + case -2: + assert left_child is not None + if get_height(left_child.get_left()) > get_height(left_child.get_right()): + root = right_rotation(root) + else: + root = lr_rotation(root) height = my_max(get_height(root.get_right()), get_height(root.get_left())) + 1 root.set_height(height) return root diff --git a/data_structures/binary_tree/treap.py b/data_structures/binary_tree/treap.py index 24f8e365a516..7f105328ccea 100644 --- a/data_structures/binary_tree/treap.py +++ b/data_structures/binary_tree/treap.py @@ -143,14 +143,15 @@ def interact_treap(root: Node | None, args: str) -> Node | None: Unknown command """ for arg in args.split(): - if arg[0] == "+": - root = insert(root, int(arg[1:])) + match arg[0]: + case "+": + root = insert(root, int(arg[1:])) - elif arg[0] == "-": - root = erase(root, int(arg[1:])) + case "-": + root = erase(root, int(arg[1:])) - else: - print("Unknown command") + case _: + print("Unknown command") return root diff --git a/data_structures/linked_list/sorted_linked_list.py b/data_structures/linked_list/sorted_linked_list.py index 539ea5a3f566..82807ff0b135 100644 --- a/data_structures/linked_list/sorted_linked_list.py +++ b/data_structures/linked_list/sorted_linked_list.py @@ -312,18 +312,19 @@ def merge(self, other_list: SortedLinkedList) -> None: print("4. Exit") choice = input("Enter your choice: ") - if choice == "1": - node_data = int(input("Enter a number: ")) - linked_list.insert(node_data) - elif choice == "2": - linked_list.display() - elif choice == "3": - node_data = int(input("Enter the data to delete: ")) - if linked_list.delete(node_data): - print(f"Node with data {node_data} deleted successfully") - else: - print(f"Node with data {node_data} not found in the list") - elif choice == "4": - break - else: - print("Wrong input") + match choice: + case "1": + node_data = int(input("Enter a number: ")) + linked_list.insert(node_data) + case "2": + linked_list.display() + case "3": + node_data = int(input("Enter the data to delete: ")) + if linked_list.delete(node_data): + print(f"Node with data {node_data} deleted successfully") + else: + print(f"Node with data {node_data} not found in the list") + case "4": + break + case _: + print("Wrong input") diff --git a/data_structures/stacks/infix_to_prefix_conversion.py b/data_structures/stacks/infix_to_prefix_conversion.py index 878473b93c19..8eb86ba60530 100644 --- a/data_structures/stacks/infix_to_prefix_conversion.py +++ b/data_structures/stacks/infix_to_prefix_conversion.py @@ -173,10 +173,11 @@ def infix_2_prefix(infix: str) -> str: reversed_infix = list(infix[::-1]) # reverse the infix equation for i in range(len(reversed_infix)): - if reversed_infix[i] == "(": - reversed_infix[i] = ")" # change "(" to ")" - elif reversed_infix[i] == ")": - reversed_infix[i] = "(" # change ")" to "(" + match reversed_infix[i]: + case "(": + reversed_infix[i] = ")" # change "(" to ")" + case ")": + reversed_infix[i] = "(" # change ")" to "(" # call infix_2_postfix on Infix, return reverse of Postfix return (infix_2_postfix("".join(reversed_infix)))[::-1] diff --git a/data_structures/stacks/stack_using_two_queues.py b/data_structures/stacks/stack_using_two_queues.py index 4b73246a045c..c6687785de37 100644 --- a/data_structures/stacks/stack_using_two_queues.py +++ b/data_structures/stacks/stack_using_two_queues.py @@ -62,24 +62,25 @@ def peek(self) -> int | None: choice = input("Enter choice (1/2/3/4): ") - if choice == "1": - element = int(input("Enter an integer to push: ").strip()) - stack.push(element) - print(f"{element} pushed onto the stack.") - elif choice == "2": - popped_element = stack.pop() - if popped_element is not None: - print(f"Popped element: {popped_element}") - else: - print("Stack is empty.") - elif choice == "3": - peeked_element = stack.peek() - if peeked_element is not None: - print(f"Top element: {peeked_element}") - else: - print("Stack is empty.") - elif choice == "4": - del stack - stack = None - else: - print("Invalid choice. Please try again.") + match choice: + case "1": + element = int(input("Enter an integer to push: ").strip()) + stack.push(element) + print(f"{element} pushed onto the stack.") + case "2": + popped_element = stack.pop() + if popped_element is not None: + print(f"Popped element: {popped_element}") + else: + print("Stack is empty.") + case "3": + peeked_element = stack.peek() + if peeked_element is not None: + print(f"Top element: {peeked_element}") + else: + print("Stack is empty.") + case "4": + del stack + stack = None + case _: + print("Invalid choice. Please try again.") diff --git a/graphics/vector3_for_2d_rendering.py b/graphics/vector3_for_2d_rendering.py index a332206e67b6..d75bc06af0d3 100644 --- a/graphics/vector3_for_2d_rendering.py +++ b/graphics/vector3_for_2d_rendering.py @@ -76,20 +76,21 @@ def rotate( ) raise TypeError(msg) angle = (angle % 360) / 450 * 180 / math.pi - if axis == "z": - new_x = x * math.cos(angle) - y * math.sin(angle) - new_y = y * math.cos(angle) + x * math.sin(angle) - new_z = z - elif axis == "x": - new_y = y * math.cos(angle) - z * math.sin(angle) - new_z = z * math.cos(angle) + y * math.sin(angle) - new_x = x - elif axis == "y": - new_x = x * math.cos(angle) - z * math.sin(angle) - new_z = z * math.cos(angle) + x * math.sin(angle) - new_y = y - else: - raise ValueError("not a valid axis, choose one of 'x', 'y', 'z'") + match axis: + case "z": + new_x = x * math.cos(angle) - y * math.sin(angle) + new_y = y * math.cos(angle) + x * math.sin(angle) + new_z = z + case "x": + new_y = y * math.cos(angle) - z * math.sin(angle) + new_z = z * math.cos(angle) + y * math.sin(angle) + new_x = x + case "y": + new_x = x * math.cos(angle) - z * math.sin(angle) + new_z = z * math.cos(angle) + x * math.sin(angle) + new_y = y + case _: + raise ValueError("not a valid axis, choose one of 'x', 'y', 'z'") return new_x, new_y, new_z diff --git a/linear_algebra/src/lib.py b/linear_algebra/src/lib.py index 01f04512b9c1..433cedbd660e 100644 --- a/linear_algebra/src/lib.py +++ b/linear_algebra/src/lib.py @@ -116,15 +116,16 @@ def __mul__(self, other: float | Vector) -> float | Vector: mul implements the scalar multiplication and the dot-product """ - if isinstance(other, (float, int)): - ans = [c * other for c in self.__components] - return Vector(ans) - elif isinstance(other, Vector) and len(self) == len(other): - size = len(self) - prods = [self.__components[i] * other.component(i) for i in range(size)] - return sum(prods) - else: # error case - raise Exception("invalid operand!") + match other: + case float() | int(): + ans = [c * other for c in self.__components] + return Vector(ans) + case Vector() if len(self) == len(other): + size = len(self) + prods = [self.__components[i] * other.component(i) for i in range(size)] + return sum(prods) + case _: # error case + raise Exception("invalid operand!") def copy(self) -> Vector: """ @@ -327,27 +328,28 @@ def __mul__(self, other: float | Vector) -> Vector | Matrix: implements the matrix-vector multiplication. implements the matrix-scalar multiplication """ - if isinstance(other, Vector): # matrix-vector - if len(other) == self.__width: - ans = zero_vector(self.__height) - for i in range(self.__height): - prods = [ - self.__matrix[i][j] * other.component(j) - for j in range(self.__width) - ] - ans.change_component(i, sum(prods)) - return ans - else: - raise Exception( - "vector must have the same size as the " - "number of columns of the matrix!" - ) - elif isinstance(other, (int, float)): # matrix-scalar - matrix = [ - [self.__matrix[i][j] * other for j in range(self.__width)] - for i in range(self.__height) - ] - return Matrix(matrix, self.__width, self.__height) + match other: + case Vector(): # matrix-vector + if len(other) == self.__width: + ans = zero_vector(self.__height) + for i in range(self.__height): + prods = [ + self.__matrix[i][j] * other.component(j) + for j in range(self.__width) + ] + ans.change_component(i, sum(prods)) + return ans + else: + raise Exception( + "vector must have the same size as the " + "number of columns of the matrix!" + ) + case int() | float(): # matrix-scalar + matrix = [ + [self.__matrix[i][j] * other for j in range(self.__width)] + for i in range(self.__height) + ] + return Matrix(matrix, self.__width, self.__height) return None def height(self) -> int: @@ -410,18 +412,20 @@ def determinant(self) -> float: raise Exception("Matrix is not square") if self.__height < 1: raise Exception("Matrix has no element") - if self.__height == 1: - return self.__matrix[0][0] - elif self.__height == 2: - return ( - self.__matrix[0][0] * self.__matrix[1][1] - - self.__matrix[0][1] * self.__matrix[1][0] - ) - else: - cofactor_prods = [ - self.__matrix[0][y] * self.cofactor(0, y) for y in range(self.__width) - ] - return sum(cofactor_prods) + match self.__height: + case 1: + return self.__matrix[0][0] + case 2: + return ( + self.__matrix[0][0] * self.__matrix[1][1] + - self.__matrix[0][1] * self.__matrix[1][0] + ) + case _: + cofactor_prods = [ + self.__matrix[0][y] * self.cofactor(0, y) + for y in range(self.__width) + ] + return sum(cofactor_prods) def square_zero_matrix(n: int) -> Matrix: diff --git a/linear_algebra/src/power_iteration.py b/linear_algebra/src/power_iteration.py index 83c2ce48c3a0..45d520510342 100644 --- a/linear_algebra/src/power_iteration.py +++ b/linear_algebra/src/power_iteration.py @@ -94,12 +94,13 @@ def test_power_iteration() -> None: complex_vector = np.array([41, 4, 20]).astype(np.complex128) for problem_type in ["real", "complex"]: - if problem_type == "real": - input_matrix = real_input_matrix - vector = real_vector - elif problem_type == "complex": - input_matrix = complex_input_matrix - vector = complex_vector + match problem_type: + case "real": + input_matrix = real_input_matrix + vector = real_vector + case "complex": + input_matrix = complex_input_matrix + vector = complex_vector # Our implementation. eigen_value, eigen_vector = power_iteration(input_matrix, vector) diff --git a/machine_learning/gradient_descent.py b/machine_learning/gradient_descent.py index 75951571400c..2cbfa3ed5612 100644 --- a/machine_learning/gradient_descent.py +++ b/machine_learning/gradient_descent.py @@ -65,10 +65,11 @@ def output(example_no, data_set): >>> output(0, "unknown") is None True """ - if data_set == "train": - return train_data[example_no][1] - elif data_set == "test": - return test_data[example_no][1] + match data_set: + case "train": + return train_data[example_no][1] + case "test": + return test_data[example_no][1] return None @@ -86,10 +87,11 @@ def calculate_hypothesis_value(example_no, data_set): >>> calculate_hypothesis_value(0, "unknown") is None True """ - if data_set == "train": - return _hypothesis_value(train_data[example_no][0]) - elif data_set == "test": - return _hypothesis_value(test_data[example_no][0]) + match data_set: + case "train": + return _hypothesis_value(train_data[example_no][0]) + case "test": + return _hypothesis_value(test_data[example_no][0]) return None diff --git a/machine_learning/q_learning.py b/machine_learning/q_learning.py index 4b10737b945f..879faee5d817 100644 --- a/machine_learning/q_learning.py +++ b/machine_learning/q_learning.py @@ -161,14 +161,15 @@ def step_env(action: int) -> tuple[State, float, bool]: """ global current_state x, y = current_state - if action == 0: # up - x = max(0, x - 1) - elif action == 1: # right - y = min(SIZE - 1, y + 1) - elif action == 2: # down - x = min(SIZE - 1, x + 1) - elif action == 3: # left - y = max(0, y - 1) + match action: + case 0: # up + x = max(0, x - 1) + case 1: # right + y = min(SIZE - 1, y + 1) + case 2: # down + x = min(SIZE - 1, x + 1) + case 3: # left + y = max(0, y - 1) next_state = (x, y) reward = 10.0 if next_state == GOAL else -1.0 done = next_state == GOAL diff --git a/machine_learning/support_vector_machines.py b/machine_learning/support_vector_machines.py index d17c9044a3e9..b64f940a515d 100644 --- a/machine_learning/support_vector_machines.py +++ b/machine_learning/support_vector_machines.py @@ -60,22 +60,23 @@ def __init__( ) -> None: self.regularization = regularization self.gamma = gamma - if kernel == "linear": - self.kernel = self.__linear - elif kernel == "rbf": - if self.gamma == 0: - raise ValueError("rbf kernel requires gamma") - if not isinstance(self.gamma, (float, int)): - raise ValueError("gamma must be float or int") - if not self.gamma > 0: - raise ValueError("gamma must be > 0") - self.kernel = self.__rbf - # in the future, there could be a default value like in sklearn - # sklear: def_gamma = 1/(n_features * X.var()) (wiki) - # previously it was 1/(n_features) - else: - msg = f"Unknown kernel: {kernel}" - raise ValueError(msg) + match kernel: + case "linear": + self.kernel = self.__linear + case "rbf": + if self.gamma == 0: + raise ValueError("rbf kernel requires gamma") + if not isinstance(self.gamma, (float, int)): + raise ValueError("gamma must be float or int") + if not self.gamma > 0: + raise ValueError("gamma must be > 0") + self.kernel = self.__rbf + # in the future, there could be a default value like in sklearn + # sklear: def_gamma = 1/(n_features * X.var()) (wiki) + # previously it was 1/(n_features) + case _: + msg = f"Unknown kernel: {kernel}" + raise ValueError(msg) # kernels def __linear(self, vector1: ndarray, vector2: ndarray) -> float: diff --git a/maths/jaccard_similarity.py b/maths/jaccard_similarity.py index 6b6243458fa8..08f7016d8595 100644 --- a/maths/jaccard_similarity.py +++ b/maths/jaccard_similarity.py @@ -65,25 +65,28 @@ def jaccard_similarity( ValueError: Set a and b must either both be sets or be either a list or a tuple. """ - if isinstance(set_a, set) and isinstance(set_b, set): - intersection_length = len(set_a.intersection(set_b)) - - if alternative_union: - union_length = len(set_a) + len(set_b) - else: - union_length = len(set_a.union(set_b)) - - return intersection_length / union_length - - elif isinstance(set_a, (list, tuple)) and isinstance(set_b, (list, tuple)): - intersection = [element for element in set_a if element in set_b] - - if alternative_union: - return len(intersection) / (len(set_a) + len(set_b)) - else: - # Cast set_a to list because tuples cannot be mutated - union = list(set_a) + [element for element in set_b if element not in set_a] - return len(intersection) / len(union) + match set_a: + case set() if isinstance(set_b, set): + intersection_length = len(set_a.intersection(set_b)) + + if alternative_union: + union_length = len(set_a) + len(set_b) + else: + union_length = len(set_a.union(set_b)) + + return intersection_length / union_length + + case list() | tuple() if isinstance(set_b, (list, tuple)): + intersection = [element for element in set_a if element in set_b] + + if alternative_union: + return len(intersection) / (len(set_a) + len(set_b)) + else: + # Cast set_a to list because tuples cannot be mutated + union = list(set_a) + [ + element for element in set_b if element not in set_a + ] + return len(intersection) / len(union) raise ValueError( "Set a and b must either both be sets or be either a list or a tuple." ) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index 453a4763accc..f1c7abd56566 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -55,10 +55,11 @@ def fibonacci_with_matrix_exponentiation(n: int, f1: int, f2: int) -> int: 89 """ # Trivial Cases - if n == 1: - return f1 - elif n == 2: - return f2 + match n: + case 1: + return f1 + case 2: + return f2 matrix = Matrix([[1, 1], [1, 0]]) matrix = modular_exponentiation(matrix, n - 2) return f2 * matrix.t[0][0] + f1 * matrix.t[0][1] @@ -81,10 +82,11 @@ def simple_fibonacci(n: int, f1: int, f2: int) -> int: 89 """ # Trivial Cases - if n == 1: - return f1 - elif n == 2: - return f2 + match n: + case 1: + return f1 + case 2: + return f2 n -= 2 diff --git a/maths/polynomials/single_indeterminate_operations.py b/maths/polynomials/single_indeterminate_operations.py index e273c5409a7f..4dffbdb4c29f 100644 --- a/maths/polynomials/single_indeterminate_operations.py +++ b/maths/polynomials/single_indeterminate_operations.py @@ -115,12 +115,13 @@ def __str__(self) -> str: else: polynomial += " - " - if i == 0: - polynomial += str(abs(self.coefficients[i])) - elif i == 1: - polynomial += str(abs(self.coefficients[i])) + "x" - else: - polynomial += str(abs(self.coefficients[i])) + "x^" + str(i) + match i: + case 0: + polynomial += str(abs(self.coefficients[i])) + case 1: + polynomial += str(abs(self.coefficients[i])) + "x" + case _: + polynomial += str(abs(self.coefficients[i])) + "x^" + str(i) return polynomial diff --git a/maths/special_numbers/kaprekar_constant.py b/maths/special_numbers/kaprekar_constant.py index d7bc7ba79a83..1d9a1f62586f 100644 --- a/maths/special_numbers/kaprekar_constant.py +++ b/maths/special_numbers/kaprekar_constant.py @@ -172,13 +172,14 @@ def main() -> None: continue iterations, sequence = kaprekar_constant(num) - if iterations == -1: - print(f" ❌ Did not reach 6174. Sequence: {sequence}") - elif iterations == 0: - print(" ✓ Already at Kaprekar's constant!") - else: - print(f" ✓ Reached 6174 in {iterations} iteration(s)") - print(f" Sequence: {' -> '.join(str(n) for n in sequence)}") + match iterations: + case -1: + print(f" ❌ Did not reach 6174. Sequence: {sequence}") + case 0: + print(" ✓ Already at Kaprekar's constant!") + case _: + print(f" ✓ Reached 6174 in {iterations} iteration(s)") + print(f" Sequence: {' -> '.join(str(n) for n in sequence)}") # Interactive mode print("\n" + "=" * 50) diff --git a/maths/special_numbers/proth_number.py b/maths/special_numbers/proth_number.py index 16bb10baa349..9104ba0fcef6 100644 --- a/maths/special_numbers/proth_number.py +++ b/maths/special_numbers/proth_number.py @@ -35,26 +35,27 @@ def proth(number: int) -> int: if number < 1: msg = f"Input value of [number={number}] must be > 0" raise ValueError(msg) - if number == 1: - return 3 - elif number == 2: - return 5 - else: - """ + match number: + case 1: + return 3 + case 2: + return 5 + case _: + """ +1 for binary starting at 0 i.e. 2^0, 2^1, etc. +1 to start the sequence at the 3rd Proth number Hence, we have a +2 in the below statement """ - block_index = int(math.log(number // 3, 2)) + 2 - - proth_list = [3, 5] - proth_index = 2 - increment = 3 - for block in range(1, block_index): - for _ in range(increment): - proth_list.append(2 ** (block + 1) + proth_list[proth_index - 1]) - proth_index += 1 - increment *= 2 + block_index = int(math.log(number // 3, 2)) + 2 + + proth_list = [3, 5] + proth_index = 2 + increment = 3 + for block in range(1, block_index): + for _ in range(increment): + proth_list.append(2 ** (block + 1) + proth_list[proth_index - 1]) + proth_index += 1 + increment *= 2 return proth_list[number - 1] diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index 60ccbcefc14b..bc6ea704fb1c 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -1,155 +1,161 @@ -from __future__ import annotations - -from decimal import Decimal - -from numpy import array - - -def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: - """ - A matrix multiplied with its inverse gives the identity matrix. - This function finds the inverse of a 2x2 and 3x3 matrix. - If the determinant of a matrix is 0, its inverse does not exist. - - Sources for fixing inaccurate float arithmetic: - https://stackoverflow.com/questions/6563058/how-do-i-use-accurate-float-arithmetic-in-python - https://docs.python.org/3/library/decimal.html - - Doctests for 2x2 - >>> inverse_of_matrix([[2, 5], [2, 0]]) - [[0.0, 0.5], [0.2, -0.2]] - >>> inverse_of_matrix([[2.5, 5], [1, 2]]) - Traceback (most recent call last): - ... - ValueError: This matrix has no inverse. - >>> inverse_of_matrix([[12, -16], [-9, 0]]) - [[0.0, -0.1111111111111111], [-0.0625, -0.08333333333333333]] - >>> inverse_of_matrix([[12, 3], [16, 8]]) - [[0.16666666666666666, -0.0625], [-0.3333333333333333, 0.25]] - >>> inverse_of_matrix([[10, 5], [3, 2.5]]) - [[0.25, -0.5], [-0.3, 1.0]] - - Doctests for 3x3 - >>> inverse_of_matrix([[2, 5, 7], [2, 0, 1], [1, 2, 3]]) - [[2.0, 1.0, -5.0], [5.0, 1.0, -12.0], [-4.0, -1.0, 10.0]] - >>> inverse_of_matrix([[1, 2, 2], [1, 2, 2], [3, 2, -1]]) - Traceback (most recent call last): - ... - ValueError: This matrix has no inverse. - - >>> inverse_of_matrix([[],[]]) - Traceback (most recent call last): - ... - ValueError: Please provide a matrix of size 2x2 or 3x3. - - >>> inverse_of_matrix([[1, 2], [3, 4], [5, 6]]) - Traceback (most recent call last): - ... - ValueError: Please provide a matrix of size 2x2 or 3x3. - - >>> inverse_of_matrix([[1, 2, 1], [0,3, 4]]) - Traceback (most recent call last): - ... - ValueError: Please provide a matrix of size 2x2 or 3x3. - - >>> inverse_of_matrix([[1, 2, 3], [7, 8, 9], [7, 8, 9]]) - Traceback (most recent call last): - ... - ValueError: This matrix has no inverse. - - >>> inverse_of_matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] - """ - - d = Decimal - - # Check if the provided matrix has 2 rows and 2 columns - # since this implementation only works for 2x2 matrices - if len(matrix) == 2 and len(matrix[0]) == 2 and len(matrix[1]) == 2: - # Calculate the determinant of the matrix - determinant = float( - d(matrix[0][0]) * d(matrix[1][1]) - d(matrix[1][0]) * d(matrix[0][1]) - ) - if determinant == 0: - raise ValueError("This matrix has no inverse.") - - # Creates a copy of the matrix with swapped positions of the elements - swapped_matrix = [[0.0, 0.0], [0.0, 0.0]] - swapped_matrix[0][0], swapped_matrix[1][1] = matrix[1][1], matrix[0][0] - swapped_matrix[1][0], swapped_matrix[0][1] = -matrix[1][0], -matrix[0][1] - - # Calculate the inverse of the matrix - return [ - [(float(d(n)) / determinant) or 0.0 for n in row] for row in swapped_matrix - ] - elif ( - len(matrix) == 3 - and len(matrix[0]) == 3 - and len(matrix[1]) == 3 - and len(matrix[2]) == 3 - ): - # Calculate the determinant of the matrix using Sarrus rule - determinant = float( - ( - (d(matrix[0][0]) * d(matrix[1][1]) * d(matrix[2][2])) - + (d(matrix[0][1]) * d(matrix[1][2]) * d(matrix[2][0])) - + (d(matrix[0][2]) * d(matrix[1][0]) * d(matrix[2][1])) - ) - - ( - (d(matrix[0][2]) * d(matrix[1][1]) * d(matrix[2][0])) - + (d(matrix[0][1]) * d(matrix[1][0]) * d(matrix[2][2])) - + (d(matrix[0][0]) * d(matrix[1][2]) * d(matrix[2][1])) - ) - ) - if determinant == 0: - raise ValueError("This matrix has no inverse.") - - # Creating cofactor matrix - cofactor_matrix = [ - [d(0.0), d(0.0), d(0.0)], - [d(0.0), d(0.0), d(0.0)], - [d(0.0), d(0.0), d(0.0)], - ] - cofactor_matrix[0][0] = (d(matrix[1][1]) * d(matrix[2][2])) - ( - d(matrix[1][2]) * d(matrix[2][1]) - ) - cofactor_matrix[0][1] = -( - (d(matrix[1][0]) * d(matrix[2][2])) - (d(matrix[1][2]) * d(matrix[2][0])) - ) - cofactor_matrix[0][2] = (d(matrix[1][0]) * d(matrix[2][1])) - ( - d(matrix[1][1]) * d(matrix[2][0]) - ) - cofactor_matrix[1][0] = -( - (d(matrix[0][1]) * d(matrix[2][2])) - (d(matrix[0][2]) * d(matrix[2][1])) - ) - cofactor_matrix[1][1] = (d(matrix[0][0]) * d(matrix[2][2])) - ( - d(matrix[0][2]) * d(matrix[2][0]) - ) - cofactor_matrix[1][2] = -( - (d(matrix[0][0]) * d(matrix[2][1])) - (d(matrix[0][1]) * d(matrix[2][0])) - ) - cofactor_matrix[2][0] = (d(matrix[0][1]) * d(matrix[1][2])) - ( - d(matrix[0][2]) * d(matrix[1][1]) - ) - cofactor_matrix[2][1] = -( - (d(matrix[0][0]) * d(matrix[1][2])) - (d(matrix[0][2]) * d(matrix[1][0])) - ) - cofactor_matrix[2][2] = (d(matrix[0][0]) * d(matrix[1][1])) - ( - d(matrix[0][1]) * d(matrix[1][0]) - ) - - # Transpose the cofactor matrix (Adjoint matrix) - adjoint_matrix = array(cofactor_matrix) - for i in range(3): - for j in range(3): - adjoint_matrix[i][j] = cofactor_matrix[j][i] - - # Inverse of the matrix using the formula (1/determinant) * adjoint matrix - inverse_matrix = array(adjoint_matrix) - for i in range(3): - for j in range(3): - inverse_matrix[i][j] /= d(determinant) - - # Calculate the inverse of the matrix - return [[float(d(n)) or 0.0 for n in row] for row in inverse_matrix] - raise ValueError("Please provide a matrix of size 2x2 or 3x3.") +from __future__ import annotations + +from decimal import Decimal + +from numpy import array + + +def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: + """ + A matrix multiplied with its inverse gives the identity matrix. + This function finds the inverse of a 2x2 and 3x3 matrix. + If the determinant of a matrix is 0, its inverse does not exist. + + Sources for fixing inaccurate float arithmetic: + https://stackoverflow.com/questions/6563058/how-do-i-use-accurate-float-arithmetic-in-python + https://docs.python.org/3/library/decimal.html + + Doctests for 2x2 + >>> inverse_of_matrix([[2, 5], [2, 0]]) + [[0.0, 0.5], [0.2, -0.2]] + >>> inverse_of_matrix([[2.5, 5], [1, 2]]) + Traceback (most recent call last): + ... + ValueError: This matrix has no inverse. + >>> inverse_of_matrix([[12, -16], [-9, 0]]) + [[0.0, -0.1111111111111111], [-0.0625, -0.08333333333333333]] + >>> inverse_of_matrix([[12, 3], [16, 8]]) + [[0.16666666666666666, -0.0625], [-0.3333333333333333, 0.25]] + >>> inverse_of_matrix([[10, 5], [3, 2.5]]) + [[0.25, -0.5], [-0.3, 1.0]] + + Doctests for 3x3 + >>> inverse_of_matrix([[2, 5, 7], [2, 0, 1], [1, 2, 3]]) + [[2.0, 1.0, -5.0], [5.0, 1.0, -12.0], [-4.0, -1.0, 10.0]] + >>> inverse_of_matrix([[1, 2, 2], [1, 2, 2], [3, 2, -1]]) + Traceback (most recent call last): + ... + ValueError: This matrix has no inverse. + + >>> inverse_of_matrix([[],[]]) + Traceback (most recent call last): + ... + ValueError: Please provide a matrix of size 2x2 or 3x3. + + >>> inverse_of_matrix([[1, 2], [3, 4], [5, 6]]) + Traceback (most recent call last): + ... + ValueError: Please provide a matrix of size 2x2 or 3x3. + + >>> inverse_of_matrix([[1, 2, 1], [0,3, 4]]) + Traceback (most recent call last): + ... + ValueError: Please provide a matrix of size 2x2 or 3x3. + + >>> inverse_of_matrix([[1, 2, 3], [7, 8, 9], [7, 8, 9]]) + Traceback (most recent call last): + ... + ValueError: This matrix has no inverse. + + >>> inverse_of_matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] + """ + + d = Decimal + + # Check if the provided matrix has 2 rows and 2 columns + # since this implementation only works for 2x2 matrices + match matrix: + case [_, _], [_, _]: + # Calculate the determinant of the matrix + determinant = float( + d(matrix[0][0]) * d(matrix[1][1]) - d(matrix[1][0]) * d(matrix[0][1]) + ) + if determinant == 0: + raise ValueError("This matrix has no inverse.") + + # Creates a copy of the matrix with swapped positions of the elements + swapped_matrix = [[0.0, 0.0], [0.0, 0.0]] + swapped_matrix[0][0], swapped_matrix[1][1] = matrix[1][1], matrix[0][0] + swapped_matrix[1][0], swapped_matrix[0][1] = -matrix[1][0], -matrix[0][1] + + # Calculate the inverse of the matrix + return [ + [(float(d(n)) / determinant) or 0.0 for n in row] + for row in swapped_matrix + ] + case _ if ( + len(matrix) == 3 + and len(matrix[0]) == 3 + and len(matrix[1]) == 3 + and len(matrix[2]) == 3 + ): + # Calculate the determinant of the matrix using Sarrus rule + determinant = float( + ( + (d(matrix[0][0]) * d(matrix[1][1]) * d(matrix[2][2])) + + (d(matrix[0][1]) * d(matrix[1][2]) * d(matrix[2][0])) + + (d(matrix[0][2]) * d(matrix[1][0]) * d(matrix[2][1])) + ) + - ( + (d(matrix[0][2]) * d(matrix[1][1]) * d(matrix[2][0])) + + (d(matrix[0][1]) * d(matrix[1][0]) * d(matrix[2][2])) + + (d(matrix[0][0]) * d(matrix[1][2]) * d(matrix[2][1])) + ) + ) + if determinant == 0: + raise ValueError("This matrix has no inverse.") + + # Creating cofactor matrix + cofactor_matrix = [ + [d(0.0), d(0.0), d(0.0)], + [d(0.0), d(0.0), d(0.0)], + [d(0.0), d(0.0), d(0.0)], + ] + cofactor_matrix[0][0] = (d(matrix[1][1]) * d(matrix[2][2])) - ( + d(matrix[1][2]) * d(matrix[2][1]) + ) + cofactor_matrix[0][1] = -( + (d(matrix[1][0]) * d(matrix[2][2])) + - (d(matrix[1][2]) * d(matrix[2][0])) + ) + cofactor_matrix[0][2] = (d(matrix[1][0]) * d(matrix[2][1])) - ( + d(matrix[1][1]) * d(matrix[2][0]) + ) + cofactor_matrix[1][0] = -( + (d(matrix[0][1]) * d(matrix[2][2])) + - (d(matrix[0][2]) * d(matrix[2][1])) + ) + cofactor_matrix[1][1] = (d(matrix[0][0]) * d(matrix[2][2])) - ( + d(matrix[0][2]) * d(matrix[2][0]) + ) + cofactor_matrix[1][2] = -( + (d(matrix[0][0]) * d(matrix[2][1])) + - (d(matrix[0][1]) * d(matrix[2][0])) + ) + cofactor_matrix[2][0] = (d(matrix[0][1]) * d(matrix[1][2])) - ( + d(matrix[0][2]) * d(matrix[1][1]) + ) + cofactor_matrix[2][1] = -( + (d(matrix[0][0]) * d(matrix[1][2])) + - (d(matrix[0][2]) * d(matrix[1][0])) + ) + cofactor_matrix[2][2] = (d(matrix[0][0]) * d(matrix[1][1])) - ( + d(matrix[0][1]) * d(matrix[1][0]) + ) + + # Transpose the cofactor matrix (Adjoint matrix) + adjoint_matrix = array(cofactor_matrix) + for i in range(3): + for j in range(3): + adjoint_matrix[i][j] = cofactor_matrix[j][i] + + # Inverse of the matrix using the formula (1/determinant) * adjoint matrix + inverse_matrix = array(adjoint_matrix) + for i in range(3): + for j in range(3): + inverse_matrix[i][j] /= d(determinant) + + # Calculate the inverse of the matrix + return [[float(d(n)) or 0.0 for n in row] for row in inverse_matrix] + raise ValueError("Please provide a matrix of size 2x2 or 3x3.") diff --git a/matrix/matrix_class.py b/matrix/matrix_class.py index 6650c5767c40..df20980d526e 100644 --- a/matrix/matrix_class.py +++ b/matrix/matrix_class.py @@ -318,26 +318,28 @@ def __sub__(self, other: Matrix) -> Matrix: ) def __mul__(self, other: Matrix | float) -> Matrix: - if isinstance(other, (int, float)): - return Matrix( - [[int(element * other) for element in row] for row in self.rows] - ) - elif isinstance(other, Matrix): - if self.num_columns != other.num_rows: - raise ValueError( - "The number of columns in the first matrix must " - "be equal to the number of rows in the second" + match other: + case int() | float(): + return Matrix( + [[int(element * other) for element in row] for row in self.rows] + ) + case Matrix(): + if self.num_columns != other.num_rows: + raise ValueError( + "The number of columns in the first matrix must " + "be equal to the number of rows in the second" + ) + return Matrix( + [ + [Matrix.dot_product(row, column) for column in other.columns()] + for row in self.rows + ] + ) + case _: + raise TypeError( + "A Matrix can only be multiplied by an int, float, or another " + "matrix" ) - return Matrix( - [ - [Matrix.dot_product(row, column) for column in other.columns()] - for row in self.rows - ] - ) - else: - raise TypeError( - "A Matrix can only be multiplied by an int, float, or another matrix" - ) def __pow__(self, other: int) -> Matrix: if not isinstance(other, int): diff --git a/matrix/sherman_morrison.py b/matrix/sherman_morrison.py index e2a09c1d0070..bbc27d5975d1 100644 --- a/matrix/sherman_morrison.py +++ b/matrix/sherman_morrison.py @@ -159,23 +159,24 @@ def __mul__(self, another: float | Matrix) -> Matrix: [-2, -2, -6] """ - if isinstance(another, (int, float)): # Scalar multiplication - result = Matrix(self.row, self.column) - for r in range(self.row): - for c in range(self.column): - result[r, c] = self[r, c] * another - return result - elif isinstance(another, Matrix): # Matrix multiplication - assert self.column == another.row - result = Matrix(self.row, another.column) - for r in range(self.row): - for c in range(another.column): - for i in range(self.column): - result[r, c] += self[r, i] * another[i, c] - return result - else: - msg = f"Unsupported type given for another ({type(another)})" - raise TypeError(msg) + match another: + case int() | float(): # Scalar multiplication + result = Matrix(self.row, self.column) + for r in range(self.row): + for c in range(self.column): + result[r, c] = self[r, c] * another + return result + case Matrix(): # Matrix multiplication + assert self.column == another.row + result = Matrix(self.row, another.column) + for r in range(self.row): + for c in range(another.column): + for i in range(self.column): + result[r, c] += self[r, i] * another[i, c] + return result + case _: + msg = f"Unsupported type given for another ({type(another)})" + raise TypeError(msg) def transpose(self) -> Matrix: """ diff --git a/neural_network/convolution_neural_network.py b/neural_network/convolution_neural_network.py index b7ef8929ced0..f1141e790d3f 100644 --- a/neural_network/convolution_neural_network.py +++ b/neural_network/convolution_neural_network.py @@ -156,12 +156,13 @@ def pooling(self, featuremaps, size_pooling, pooling_type="average_pool"): i_focus : i_focus + size_pooling, j_focus : j_focus + size_pooling, ] - if pooling_type == "average_pool": - # average pooling - map_pooled.append(np.average(focus)) - elif pooling_type == "max_pooling": - # max pooling - map_pooled.append(np.max(focus)) + match pooling_type: + case "average_pool": + # average pooling + map_pooled.append(np.average(focus)) + case "max_pooling": + # max pooling + map_pooled.append(np.max(focus)) map_pooled = np.asmatrix(map_pooled).reshape(size_pooled, size_pooled) featuremap_pooled.append(map_pooled) return featuremap_pooled diff --git a/other/davis_putnam_logemann_loveland.py b/other/davis_putnam_logemann_loveland.py index 7d0bcce15a29..86b0337988f5 100644 --- a/other/davis_putnam_logemann_loveland.py +++ b/other/davis_putnam_logemann_loveland.py @@ -266,11 +266,12 @@ def find_unit_clauses( else: f_count, n_count = 0, 0 for literal, value in clause.literals.items(): - if value is False: - f_count += 1 - elif value is None: - sym = literal - n_count += 1 + match value: + case False: + f_count += 1 + case None: + sym = literal + n_count += 1 if f_count == len(clause) - 1 and n_count == 1: unit_symbols.append(sym) assignment: dict[str, bool | None] = {} @@ -305,11 +306,12 @@ def dpll_algorithm( check_clause_all_true = True for clause in clauses: clause_check = clause.evaluate(model) - if clause_check is False: - return False, None - elif clause_check is None: - check_clause_all_true = False - continue + match clause_check: + case False: + return False, None + case None: + check_clause_all_true = False + continue if check_clause_all_true: return True, model diff --git a/other/gauss_easter.py b/other/gauss_easter.py index 8c8c37c92796..26b00c0d2094 100644 --- a/other/gauss_easter.py +++ b/other/gauss_easter.py @@ -44,14 +44,15 @@ def gauss_easter(year: int) -> datetime: + century_starting_point ) % 7 - if days_to_add == 29 and days_from_phm_to_sunday == 6: - return datetime(year, 4, 19, tzinfo=UTC) - elif days_to_add == 28 and days_from_phm_to_sunday == 6: - return datetime(year, 4, 18, tzinfo=UTC) - else: - return datetime(year, 3, 22, tzinfo=UTC) + timedelta( - days=int(days_to_add + days_from_phm_to_sunday) - ) + match days_to_add: + case 29 if days_from_phm_to_sunday == 6: + return datetime(year, 4, 19, tzinfo=UTC) + case 28 if days_from_phm_to_sunday == 6: + return datetime(year, 4, 18, tzinfo=UTC) + case _: + return datetime(year, 3, 22, tzinfo=UTC) + timedelta( + days=int(days_to_add + days_from_phm_to_sunday) + ) if __name__ == "__main__": diff --git a/other/guess_the_number_search.py b/other/guess_the_number_search.py index 01e8898bbb8a..eefaedf4ad00 100644 --- a/other/guess_the_number_search.py +++ b/other/guess_the_number_search.py @@ -140,12 +140,13 @@ def answer(number: int) -> str: number = get_avg(last_lowest, last_highest) last_numbers.append(number) - if answer(number) == "low": - last_lowest = number - elif answer(number) == "high": - last_highest = number - else: - break + match answer(number): + case "low": + last_lowest = number + case "high": + last_highest = number + case _: + break print(f"guess the number : {last_numbers[-1]}") print(f"details : {last_numbers!s}") diff --git a/other/scoring_algorithm.py b/other/scoring_algorithm.py index 0185d7a2e0c0..ed850f7c73d9 100644 --- a/other/scoring_algorithm.py +++ b/other/scoring_algorithm.py @@ -53,24 +53,25 @@ def calculate_each_score( score: list[float] = [] # for weight 0 score is 1 - actual score - if weight == 0: - for item in dlist: - try: - score.append(1 - ((item - mind) / (maxd - mind))) - except ZeroDivisionError: - score.append(1) - - elif weight == 1: - for item in dlist: - try: - score.append((item - mind) / (maxd - mind)) - except ZeroDivisionError: - score.append(0) - - # weight not 0 or 1 - else: - msg = f"Invalid weight of {weight:f} provided" - raise ValueError(msg) + match weight: + case 0: + for item in dlist: + try: + score.append(1 - ((item - mind) / (maxd - mind))) + except ZeroDivisionError: + score.append(1) + + case 1: + for item in dlist: + try: + score.append((item - mind) / (maxd - mind)) + except ZeroDivisionError: + score.append(0) + + # weight not 0 or 1 + case _: + msg = f"Invalid weight of {weight:f} provided" + raise ValueError(msg) score_lists.append(score) diff --git a/physics/boyles_law.py b/physics/boyles_law.py index 35b74f4585ab..b21b92966538 100644 --- a/physics/boyles_law.py +++ b/physics/boyles_law.py @@ -155,26 +155,27 @@ def boyles_law(values: dict[str, float]) -> dict[str, str]: check_validity(values) target = find_target_variable(values) float_precision = ".3f" - if target == "p1": - p1 = float( - format((values["p2"] * values["v2"]) / values["v1"], float_precision) - ) - return {"p1": f"{p1} Pa"} - elif target == "v1": - v1 = float( - format((values["p2"] * values["v2"]) / values["p1"], float_precision) - ) - return {"v1": f"{v1} L"} - elif target == "p2": - p2 = float( - format((values["p1"] * values["v1"]) / values["v2"], float_precision) - ) - return {"p2": f"{p2} Pa"} - else: - v2 = float( - format((values["p1"] * values["v1"]) / values["p2"], float_precision) - ) - return {"v2": f"{v2} L"} + match target: + case "p1": + p1 = float( + format((values["p2"] * values["v2"]) / values["v1"], float_precision) + ) + return {"p1": f"{p1} Pa"} + case "v1": + v1 = float( + format((values["p2"] * values["v2"]) / values["p1"], float_precision) + ) + return {"v1": f"{v1} L"} + case "p2": + p2 = float( + format((values["p1"] * values["v1"]) / values["v2"], float_precision) + ) + return {"p2": f"{p2} Pa"} + case _: + v2 = float( + format((values["p1"] * values["v1"]) / values["p2"], float_precision) + ) + return {"v2": f"{v2} L"} if __name__ == "__main__": diff --git a/physics/first_law_of_thermodynamics.py b/physics/first_law_of_thermodynamics.py index 6c5e48d2430e..14a7ee249719 100644 --- a/physics/first_law_of_thermodynamics.py +++ b/physics/first_law_of_thermodynamics.py @@ -50,32 +50,37 @@ def __categorize_system(argument_value: float, argument_name: str) -> None: ValueError: Should be 'work', 'heat', or 'internal_energy_variation'. """ - if argument_name == "work": - if argument_value == 0: - print("The system is isochoric (constant volume).") - elif argument_value > 0: - print("The system is expanding.") - elif argument_value < 0: - print("The system is compressing.") - - elif argument_name == "heat": - if argument_value == 0: - print("The system is adiabatic (no heat exchange).") - elif argument_value > 0: - print("The system is endothermic (absorbing heat).") - elif argument_value < 0: - print("The system is exothermic (releasing heat).") - - elif argument_name == "internal_energy_variation": - if argument_value == 0: - print("The system is isothermic (constant internal energy)") - elif argument_value > 0: - print("The internal energy of the system is increasing. It heating up.") - elif argument_value < 0: - print("The internal energy of the system is decreasing. It cooling down.") - - else: - raise ValueError("Should be 'work', 'heat', or 'internal_energy_variation'.") + match argument_name: + case "work": + if argument_value == 0: + print("The system is isochoric (constant volume).") + elif argument_value > 0: + print("The system is expanding.") + elif argument_value < 0: + print("The system is compressing.") + + case "heat": + if argument_value == 0: + print("The system is adiabatic (no heat exchange).") + elif argument_value > 0: + print("The system is endothermic (absorbing heat).") + elif argument_value < 0: + print("The system is exothermic (releasing heat).") + + case "internal_energy_variation": + if argument_value == 0: + print("The system is isothermic (constant internal energy)") + elif argument_value > 0: + print("The internal energy of the system is increasing. It heating up.") + elif argument_value < 0: + print( + "The internal energy of the system is decreasing. It cooling down." + ) + + case _: + raise ValueError( + "Should be 'work', 'heat', or 'internal_energy_variation'." + ) def work(heat: float, internal_energy_variation: float) -> float: diff --git a/project_euler/problem_054/sol1.py b/project_euler/problem_054/sol1.py index d0c023f04566..a2aa239f44f8 100644 --- a/project_euler/problem_054/sol1.py +++ b/project_euler/problem_054/sol1.py @@ -211,17 +211,18 @@ def hand_name(self) -> str: high = PokerHand._CARD_NAME[self._high_card] pair1 = PokerHand._CARD_NAME[self._first_pair] pair2 = PokerHand._CARD_NAME[self._second_pair] - if self._hand_type in [22, 19, 18]: - return name + f", {high}-high" - elif self._hand_type in [21, 17, 15]: - return name + f", {pair1}s" - elif self._hand_type in [20, 16]: - join = "over" if self._hand_type == 20 else "and" - return name + f", {pair1}s {join} {pair2}s" - elif self._hand_type == 23: - return name - else: - return name + f", {high}" + match self._hand_type: + case 22 | 19 | 18: + return name + f", {high}-high" + case 21 | 17 | 15: + return name + f", {pair1}s" + case 20 | 16: + join = "over" if self._hand_type == 20 else "and" + return name + f", {pair1}s {join} {pair2}s" + case 23: + return name + case _: + return name + f", {high}" def _compare_cards(self, other: PokerHand) -> str: # Enumerate gives us the index as well as the element of a list diff --git a/project_euler/problem_089/sol1.py b/project_euler/problem_089/sol1.py index 123159bdce09..81964d004d4c 100644 --- a/project_euler/problem_089/sol1.py +++ b/project_euler/problem_089/sol1.py @@ -76,12 +76,13 @@ def generate_roman_numerals(num: int) -> str: num %= 1000 c_count = num // 100 - if c_count == 9: - numerals += "CM" - c_count -= 9 - elif c_count == 4: - numerals += "CD" - c_count -= 4 + match c_count: + case 9: + numerals += "CM" + c_count -= 9 + case 4: + numerals += "CD" + c_count -= 4 if c_count >= 5: numerals += "D" c_count -= 5 @@ -89,24 +90,26 @@ def generate_roman_numerals(num: int) -> str: num %= 100 x_count = num // 10 - if x_count == 9: - numerals += "XC" - x_count -= 9 - elif x_count == 4: - numerals += "XL" - x_count -= 4 + match x_count: + case 9: + numerals += "XC" + x_count -= 9 + case 4: + numerals += "XL" + x_count -= 4 if x_count >= 5: numerals += "L" x_count -= 5 numerals += x_count * "X" num %= 10 - if num == 9: - numerals += "IX" - num -= 9 - elif num == 4: - numerals += "IV" - num -= 4 + match num: + case 9: + numerals += "IX" + num -= 9 + case 4: + numerals += "IV" + num -= 4 if num >= 5: numerals += "V" num -= 5 diff --git a/scheduling/cpuschedulingalgorithms.py b/scheduling/cpuschedulingalgorithms.py index aba85b482230..417c8fda25de 100644 --- a/scheduling/cpuschedulingalgorithms.py +++ b/scheduling/cpuschedulingalgorithms.py @@ -39,18 +39,19 @@ def simulate(self) -> Generator[tuple[int, str | None, list[str]]]: [(0, 'P1', []), (1, 'P1', [])] """ algo = self.algorithm.lower() - if algo == "fcfs": - yield from self._simulate_fcfs() - elif algo == "sjf (non-preemptive)": - yield from self._simulate_sjf_np() - elif algo == "sjf (preemptive)": - yield from self._simulate_sjf_p() - elif algo == "priority (non-preemptive)": - yield from self._simulate_priority_np() - elif algo == "priority (preemptive)": - yield from self._simulate_priority_p() - elif algo == "round robin": - yield from self._simulate_rr() + match algo: + case "fcfs": + yield from self._simulate_fcfs() + case "sjf (non-preemptive)": + yield from self._simulate_sjf_np() + case "sjf (preemptive)": + yield from self._simulate_sjf_p() + case "priority (non-preemptive)": + yield from self._simulate_priority_np() + case "priority (preemptive)": + yield from self._simulate_priority_p() + case "round robin": + yield from self._simulate_rr() self._calculate_stats() # first come first serve diff --git a/scripts/hacktoberfest_prep_update.py b/scripts/hacktoberfest_prep_update.py index a63e7b3eacc8..2af260c56adc 100644 --- a/scripts/hacktoberfest_prep_update.py +++ b/scripts/hacktoberfest_prep_update.py @@ -291,13 +291,14 @@ async def refresh_checkboxes( states: dict[int, str | None] = {} unresolved = 0 for number, result in zip(pending, resolved): - if isinstance(result, BestEffortError): - unresolved += 1 - states[number] = None - elif isinstance(result, BaseException): - raise result - else: - states[number] = result + match result: + case BestEffortError(): + unresolved += 1 + states[number] = None + case BaseException(): + raise result + case _: + states[number] = result if unresolved: _log(f" ...{unresolved} row(s) left unchanged (API unavailable).") diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 7b2252a68be2..3897f5501d3b 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -47,12 +47,13 @@ def fibonacci(k: int) -> int: raise TypeError("k must be an integer.") if k < 0: raise ValueError("k integer must be greater or equal to zero.") - if k == 0: - return 0 - elif k == 1: - return 1 - else: - return fibonacci(k - 1) + fibonacci(k - 2) + match k: + case 0: + return 0 + case 1: + return 1 + case _: + return fibonacci(k - 1) + fibonacci(k - 2) def fibonacci_search(arr: list, val: int) -> int: diff --git a/sorts/external_sort.py b/sorts/external_sort.py index 3ec4391d750b..6591b15f9832 100644 --- a/sorts/external_sort.py +++ b/sorts/external_sort.py @@ -126,14 +126,15 @@ def get_number_blocks(self, filename, block_size): def parse_memory(string): - if string[-1].lower() == "k": - return int(string[:-1]) * 1024 - elif string[-1].lower() == "m": - return int(string[:-1]) * 1024 * 1024 - elif string[-1].lower() == "g": - return int(string[:-1]) * 1024 * 1024 * 1024 - else: - return int(string) + match string[-1].lower(): + case "k": + return int(string[:-1]) * 1024 + case "m": + return int(string[:-1]) * 1024 * 1024 + case "g": + return int(string[:-1]) * 1024 * 1024 * 1024 + case _: + return int(string) def main() -> None: diff --git a/strings/min_cost_string_conversion.py b/strings/min_cost_string_conversion.py index f4e20e09fd5d..9feb68a24d24 100644 --- a/strings/min_cost_string_conversion.py +++ b/strings/min_cost_string_conversion.py @@ -133,36 +133,37 @@ def assemble_transformation(ops: list[list[str]], i: int, j: int) -> list[str]: for op in sequence: print("".join(string)) - if op[0] == "C": - file.write("%-16s" % "Copy %c" % op[1]) # noqa: UP031 - file.write("\t\t\t" + "".join(string)) - file.write("\r\n") + match op[0]: + case "C": + file.write("%-16s" % "Copy %c" % op[1]) # noqa: UP031 + file.write("\t\t\t" + "".join(string)) + file.write("\r\n") - cost -= 1 - elif op[0] == "R": - string[i] = op[2] + cost -= 1 + case "R": + string[i] = op[2] - file.write("%-16s" % ("Replace %c" % op[1] + " with " + str(op[2]))) # noqa: UP031 - file.write("\t\t" + "".join(string)) - file.write("\r\n") + file.write("%-16s" % ("Replace %c" % op[1] + " with " + str(op[2]))) # noqa: UP031 + file.write("\t\t" + "".join(string)) + file.write("\r\n") - cost += 1 - elif op[0] == "D": - string.pop(i) + cost += 1 + case "D": + string.pop(i) - file.write("%-16s" % "Delete %c" % op[1]) # noqa: UP031 - file.write("\t\t\t" + "".join(string)) - file.write("\r\n") + file.write("%-16s" % "Delete %c" % op[1]) # noqa: UP031 + file.write("\t\t\t" + "".join(string)) + file.write("\r\n") - cost += 2 - else: - string.insert(i, op[1]) + cost += 2 + case _: + string.insert(i, op[1]) - file.write("%-16s" % "Insert %c" % op[1]) # noqa: UP031 - file.write("\t\t\t" + "".join(string)) - file.write("\r\n") + file.write("%-16s" % "Insert %c" % op[1]) # noqa: UP031 + file.write("\t\t\t" + "".join(string)) + file.write("\r\n") - cost += 2 + cost += 2 i += 1