Merge branch 'TheAlgorithms:master' into fix-mypy-errs-5

This commit is contained in:
Tianyi Zheng 2023-04-01 12:49:28 -04:00 committed by GitHub
commit 345c1dd847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 784 additions and 164 deletions

4
.github/stale.yml vendored
View File

@ -45,7 +45,7 @@ pulls:
closeComment: > closeComment: >
Please reopen this pull request once you commit the changes requested Please reopen this pull request once you commit the changes requested
or make improvements on the code. If this is not the case and you need or make improvements on the code. If this is not the case and you need
some help, feel free to seek help from our [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im) some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms/community)
or ping one of the reviewers. Thank you for your contributions! or ping one of the reviewers. Thank you for your contributions!
issues: issues:
@ -59,5 +59,5 @@ issues:
closeComment: > closeComment: >
Please reopen this issue once you add more information and updates here. Please reopen this issue once you add more information and updates here.
If this is not the case and you need some help, feel free to seek help If this is not the case and you need some help, feel free to seek help
from our [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im) or ping one of the from our [Gitter](https://gitter.im/TheAlgorithms/community) or ping one of the
reviewers. Thank you for your contributions! reviewers. Thank you for your contributions!

View File

@ -2,7 +2,7 @@
## Before contributing ## Before contributing
Welcome to [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python)! Before sending your pull requests, make sure that you __read the whole guidelines__. If you have any doubt on the contributing guide, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Python/issues/new) or ask the community in [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im). Welcome to [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python)! Before sending your pull requests, make sure that you __read the whole guidelines__. If you have any doubt on the contributing guide, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Python/issues/new) or ask the community in [Gitter](https://gitter.im/TheAlgorithms/community).
## Contributing ## Contributing
@ -176,7 +176,7 @@ We want your work to be readable by others; therefore, we encourage you to note
- Most importantly, - Most importantly,
- __Be consistent in the use of these guidelines when submitting.__ - __Be consistent in the use of these guidelines when submitting.__
- __Join__ us on [Discord](https://discord.com/invite/c7MnfGFGa6) and [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im) __now!__ - __Join__ us on [Discord](https://discord.com/invite/c7MnfGFGa6) and [Gitter](https://gitter.im/TheAlgorithms/community) __now!__
- Happy coding! - Happy coding!
Writer [@poyea](https://github.com/poyea), Jun 2019. Writer [@poyea](https://github.com/poyea), Jun 2019.

View File

@ -317,6 +317,7 @@
* [Longest Sub Array](dynamic_programming/longest_sub_array.py) * [Longest Sub Array](dynamic_programming/longest_sub_array.py)
* [Matrix Chain Order](dynamic_programming/matrix_chain_order.py) * [Matrix Chain Order](dynamic_programming/matrix_chain_order.py)
* [Max Non Adjacent Sum](dynamic_programming/max_non_adjacent_sum.py) * [Max Non Adjacent Sum](dynamic_programming/max_non_adjacent_sum.py)
* [Max Product Subarray](dynamic_programming/max_product_subarray.py)
* [Max Sub Array](dynamic_programming/max_sub_array.py) * [Max Sub Array](dynamic_programming/max_sub_array.py)
* [Max Sum Contiguous Subsequence](dynamic_programming/max_sum_contiguous_subsequence.py) * [Max Sum Contiguous Subsequence](dynamic_programming/max_sum_contiguous_subsequence.py)
* [Min Distance Up Bottom](dynamic_programming/min_distance_up_bottom.py) * [Min Distance Up Bottom](dynamic_programming/min_distance_up_bottom.py)
@ -936,6 +937,8 @@
* [Sol1](project_euler/problem_091/sol1.py) * [Sol1](project_euler/problem_091/sol1.py)
* Problem 092 * Problem 092
* [Sol1](project_euler/problem_092/sol1.py) * [Sol1](project_euler/problem_092/sol1.py)
* Problem 094
* [Sol1](project_euler/problem_094/sol1.py)
* Problem 097 * Problem 097
* [Sol1](project_euler/problem_097/sol1.py) * [Sol1](project_euler/problem_097/sol1.py)
* Problem 099 * Problem 099
@ -990,6 +993,8 @@
* [Sol1](project_euler/problem_174/sol1.py) * [Sol1](project_euler/problem_174/sol1.py)
* Problem 180 * Problem 180
* [Sol1](project_euler/problem_180/sol1.py) * [Sol1](project_euler/problem_180/sol1.py)
* Problem 187
* [Sol1](project_euler/problem_187/sol1.py)
* Problem 188 * Problem 188
* [Sol1](project_euler/problem_188/sol1.py) * [Sol1](project_euler/problem_188/sol1.py)
* Problem 191 * Problem 191
@ -1014,6 +1019,8 @@
* [Sol1](project_euler/problem_587/sol1.py) * [Sol1](project_euler/problem_587/sol1.py)
* Problem 686 * Problem 686
* [Sol1](project_euler/problem_686/sol1.py) * [Sol1](project_euler/problem_686/sol1.py)
* Problem 800
* [Sol1](project_euler/problem_800/sol1.py)
## Quantum ## Quantum
* [Bb84](quantum/bb84.py) * [Bb84](quantum/bb84.py)

View File

@ -16,7 +16,7 @@
<a href="https://discord.gg/c7MnfGFGa6"> <a href="https://discord.gg/c7MnfGFGa6">
<img src="https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square" height="20" alt="Discord chat"> <img src="https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square" height="20" alt="Discord chat">
</a> </a>
<a href="https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im"> <a href="https://gitter.im/TheAlgorithms/community">
<img src="https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square" height="20" alt="Gitter chat"> <img src="https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square" height="20" alt="Gitter chat">
</a> </a>
<!-- Second row: --> <!-- Second row: -->
@ -42,7 +42,7 @@ Read through our [Contribution Guidelines](CONTRIBUTING.md) before you contribut
## Community Channels ## Community Channels
We are on [Discord](https://discord.gg/c7MnfGFGa6) and [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im)! Community channels are a great way for you to ask questions and get help. Please join us! We are on [Discord](https://discord.gg/c7MnfGFGa6) and [Gitter](https://gitter.im/TheAlgorithms/community)! Community channels are a great way for you to ask questions and get help. Please join us!
## List of Algorithms ## List of Algorithms

View File

@ -1,62 +1,101 @@
"""Lower-Upper (LU) Decomposition. """
Lowerupper (LU) decomposition factors a matrix as a product of a lower
triangular matrix and an upper triangular matrix. A square matrix has an LU
decomposition under the following conditions:
- If the matrix is invertible, then it has an LU decomposition if and only
if all of its leading principal minors are non-zero (see
https://en.wikipedia.org/wiki/Minor_(linear_algebra) for an explanation of
leading principal minors of a matrix).
- If the matrix is singular (i.e., not invertible) and it has a rank of k
(i.e., it has k linearly independent columns), then it has an LU
decomposition if its first k leading principal minors are non-zero.
Reference: This algorithm will simply attempt to perform LU decomposition on any square
- https://en.wikipedia.org/wiki/LU_decomposition matrix and raise an error if no such decomposition exists.
Reference: https://en.wikipedia.org/wiki/LU_decomposition
""" """
from __future__ import annotations from __future__ import annotations
import numpy as np import numpy as np
from numpy import float64
from numpy.typing import ArrayLike
def lower_upper_decomposition( def lower_upper_decomposition(table: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
table: ArrayLike[float64], """
) -> tuple[ArrayLike[float64], ArrayLike[float64]]: Perform LU decomposition on a given matrix and raises an error if the matrix
"""Lower-Upper (LU) Decomposition isn't square or if no such decomposition exists
Example:
>>> matrix = np.array([[2, -2, 1], [0, 1, 2], [5, 3, 1]]) >>> matrix = np.array([[2, -2, 1], [0, 1, 2], [5, 3, 1]])
>>> outcome = lower_upper_decomposition(matrix) >>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
>>> outcome[0] >>> lower_mat
array([[1. , 0. , 0. ], array([[1. , 0. , 0. ],
[0. , 1. , 0. ], [0. , 1. , 0. ],
[2.5, 8. , 1. ]]) [2.5, 8. , 1. ]])
>>> outcome[1] >>> upper_mat
array([[ 2. , -2. , 1. ], array([[ 2. , -2. , 1. ],
[ 0. , 1. , 2. ], [ 0. , 1. , 2. ],
[ 0. , 0. , -17.5]]) [ 0. , 0. , -17.5]])
>>> matrix = np.array([[4, 3], [6, 3]])
>>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
>>> lower_mat
array([[1. , 0. ],
[1.5, 1. ]])
>>> upper_mat
array([[ 4. , 3. ],
[ 0. , -1.5]])
# Matrix is not square
>>> matrix = np.array([[2, -2, 1], [0, 1, 2]]) >>> matrix = np.array([[2, -2, 1], [0, 1, 2]])
>>> lower_upper_decomposition(matrix) >>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: 'table' has to be of square shaped array but got a 2x3 array: ValueError: 'table' has to be of square shaped array but got a 2x3 array:
[[ 2 -2 1] [[ 2 -2 1]
[ 0 1 2]] [ 0 1 2]]
# Matrix is invertible, but its first leading principal minor is 0
>>> matrix = np.array([[0, 1], [1, 0]])
>>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
Traceback (most recent call last):
...
ArithmeticError: No LU decomposition exists
# Matrix is singular, but its first leading principal minor is 1
>>> matrix = np.array([[1, 0], [1, 0]])
>>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
>>> lower_mat
array([[1., 0.],
[1., 1.]])
>>> upper_mat
array([[1., 0.],
[0., 0.]])
# Matrix is singular, but its first leading principal minor is 0
>>> matrix = np.array([[0, 1], [0, 1]])
>>> lower_mat, upper_mat = lower_upper_decomposition(matrix)
Traceback (most recent call last):
...
ArithmeticError: No LU decomposition exists
""" """
# Table that contains our data # Ensure that table is a square array
# Table has to be a square array so we need to check first
rows, columns = np.shape(table) rows, columns = np.shape(table)
if rows != columns: if rows != columns:
raise ValueError( raise ValueError(
f"'table' has to be of square shaped array but got a {rows}x{columns} " f"'table' has to be of square shaped array but got a "
+ f"array:\n{table}" f"{rows}x{columns} array:\n{table}"
) )
lower = np.zeros((rows, columns)) lower = np.zeros((rows, columns))
upper = np.zeros((rows, columns)) upper = np.zeros((rows, columns))
for i in range(columns): for i in range(columns):
for j in range(i): for j in range(i):
total = 0 total = sum(lower[i][k] * upper[k][j] for k in range(j))
for k in range(j): if upper[j][j] == 0:
total += lower[i][k] * upper[k][j] raise ArithmeticError("No LU decomposition exists")
lower[i][j] = (table[i][j] - total) / upper[j][j] lower[i][j] = (table[i][j] - total) / upper[j][j]
lower[i][i] = 1 lower[i][i] = 1
for j in range(i, columns): for j in range(i, columns):
total = 0 total = sum(lower[i][k] * upper[k][j] for k in range(j))
for k in range(i):
total += lower[i][k] * upper[k][j]
upper[i][j] = table[i][j] - total upper[i][j] = table[i][j] - total
return lower, upper return lower, upper

View File

@ -93,7 +93,7 @@ if __name__ == "__main__":
test_image = tf.keras.preprocessing.image.img_to_array(test_image) test_image = tf.keras.preprocessing.image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis=0) test_image = np.expand_dims(test_image, axis=0)
result = classifier.predict(test_image) result = classifier.predict(test_image)
training_set.class_indices # training_set.class_indices
if result[0][0] == 0: if result[0][0] == 0:
prediction = "Normal" prediction = "Normal"
if result[0][0] == 1: if result[0][0] == 1:

View File

@ -24,7 +24,7 @@ class CircularLinkedList:
break break
def __len__(self) -> int: def __len__(self) -> int:
return len(tuple(iter(self))) return sum(1 for _ in self)
def __repr__(self): def __repr__(self):
return "->".join(str(item) for item in iter(self)) return "->".join(str(item) for item in iter(self))

View File

@ -51,7 +51,7 @@ class DoublyLinkedList:
>>> len(linked_list) == 5 >>> len(linked_list) == 5
True True
""" """
return len(tuple(iter(self))) return sum(1 for _ in self)
def insert_at_head(self, data): def insert_at_head(self, data):
self.insert_at_nth(0, data) self.insert_at_nth(0, data)
@ -81,7 +81,9 @@ class DoublyLinkedList:
.... ....
IndexError: list index out of range IndexError: list index out of range
""" """
if not 0 <= index <= len(self): length = len(self)
if not 0 <= index <= length:
raise IndexError("list index out of range") raise IndexError("list index out of range")
new_node = Node(data) new_node = Node(data)
if self.head is None: if self.head is None:
@ -90,7 +92,7 @@ class DoublyLinkedList:
self.head.previous = new_node self.head.previous = new_node
new_node.next = self.head new_node.next = self.head
self.head = new_node self.head = new_node
elif index == len(self): elif index == length:
self.tail.next = new_node self.tail.next = new_node
new_node.previous = self.tail new_node.previous = self.tail
self.tail = new_node self.tail = new_node
@ -131,15 +133,17 @@ class DoublyLinkedList:
.... ....
IndexError: list index out of range IndexError: list index out of range
""" """
if not 0 <= index <= len(self) - 1: length = len(self)
if not 0 <= index <= length - 1:
raise IndexError("list index out of range") raise IndexError("list index out of range")
delete_node = self.head # default first node delete_node = self.head # default first node
if len(self) == 1: if length == 1:
self.head = self.tail = None self.head = self.tail = None
elif index == 0: elif index == 0:
self.head = self.head.next self.head = self.head.next
self.head.previous = None self.head.previous = None
elif index == len(self) - 1: elif index == length - 1:
delete_node = self.tail delete_node = self.tail
self.tail = self.tail.previous self.tail = self.tail.previous
self.tail.next = None self.tail.next = None

View File

@ -44,7 +44,7 @@ class SortedLinkedList:
>>> len(SortedLinkedList(test_data_odd)) >>> len(SortedLinkedList(test_data_odd))
8 8
""" """
return len(tuple(iter(self))) return sum(1 for _ in self)
def __str__(self) -> str: def __str__(self) -> str:
""" """

View File

@ -72,7 +72,7 @@ class LinkedList:
>>> len(linked_list) >>> len(linked_list)
0 0
""" """
return len(tuple(iter(self))) return sum(1 for _ in self)
def __repr__(self) -> str: def __repr__(self) -> str:
""" """

View File

@ -18,60 +18,61 @@ def gen_gaussian_kernel(k_size, sigma):
return g return g
def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): def suppress_non_maximum(image_shape, gradient_direction, sobel_grad):
image_row, image_col = image.shape[0], image.shape[1]
# gaussian_filter
gaussian_out = img_convolve(image, gen_gaussian_kernel(9, sigma=1.4))
# get the gradient and degree by sobel_filter
sobel_grad, sobel_theta = sobel_filter(gaussian_out)
gradient_direction = np.rad2deg(sobel_theta)
gradient_direction += PI
dst = np.zeros((image_row, image_col))
""" """
Non-maximum suppression. If the edge strength of the current pixel is the largest Non-maximum suppression. If the edge strength of the current pixel is the largest
compared to the other pixels in the mask with the same direction, the value will be compared to the other pixels in the mask with the same direction, the value will be
preserved. Otherwise, the value will be suppressed. preserved. Otherwise, the value will be suppressed.
""" """
for row in range(1, image_row - 1): destination = np.zeros(image_shape)
for col in range(1, image_col - 1):
for row in range(1, image_shape[0] - 1):
for col in range(1, image_shape[1] - 1):
direction = gradient_direction[row, col] direction = gradient_direction[row, col]
if ( if (
0 <= direction < 22.5 0 <= direction < PI / 8
or 15 * PI / 8 <= direction <= 2 * PI or 15 * PI / 8 <= direction <= 2 * PI
or 7 * PI / 8 <= direction <= 9 * PI / 8 or 7 * PI / 8 <= direction <= 9 * PI / 8
): ):
w = sobel_grad[row, col - 1] w = sobel_grad[row, col - 1]
e = sobel_grad[row, col + 1] e = sobel_grad[row, col + 1]
if sobel_grad[row, col] >= w and sobel_grad[row, col] >= e: if sobel_grad[row, col] >= w and sobel_grad[row, col] >= e:
dst[row, col] = sobel_grad[row, col] destination[row, col] = sobel_grad[row, col]
elif (PI / 8 <= direction < 3 * PI / 8) or ( elif (
9 * PI / 8 <= direction < 11 * PI / 8 PI / 8 <= direction < 3 * PI / 8
or 9 * PI / 8 <= direction < 11 * PI / 8
): ):
sw = sobel_grad[row + 1, col - 1] sw = sobel_grad[row + 1, col - 1]
ne = sobel_grad[row - 1, col + 1] ne = sobel_grad[row - 1, col + 1]
if sobel_grad[row, col] >= sw and sobel_grad[row, col] >= ne: if sobel_grad[row, col] >= sw and sobel_grad[row, col] >= ne:
dst[row, col] = sobel_grad[row, col] destination[row, col] = sobel_grad[row, col]
elif (3 * PI / 8 <= direction < 5 * PI / 8) or ( elif (
11 * PI / 8 <= direction < 13 * PI / 8 3 * PI / 8 <= direction < 5 * PI / 8
or 11 * PI / 8 <= direction < 13 * PI / 8
): ):
n = sobel_grad[row - 1, col] n = sobel_grad[row - 1, col]
s = sobel_grad[row + 1, col] s = sobel_grad[row + 1, col]
if sobel_grad[row, col] >= n and sobel_grad[row, col] >= s: if sobel_grad[row, col] >= n and sobel_grad[row, col] >= s:
dst[row, col] = sobel_grad[row, col] destination[row, col] = sobel_grad[row, col]
elif (5 * PI / 8 <= direction < 7 * PI / 8) or ( elif (
13 * PI / 8 <= direction < 15 * PI / 8 5 * PI / 8 <= direction < 7 * PI / 8
or 13 * PI / 8 <= direction < 15 * PI / 8
): ):
nw = sobel_grad[row - 1, col - 1] nw = sobel_grad[row - 1, col - 1]
se = sobel_grad[row + 1, col + 1] se = sobel_grad[row + 1, col + 1]
if sobel_grad[row, col] >= nw and sobel_grad[row, col] >= se: if sobel_grad[row, col] >= nw and sobel_grad[row, col] >= se:
dst[row, col] = sobel_grad[row, col] destination[row, col] = sobel_grad[row, col]
return destination
def detect_high_low_threshold(
image_shape, destination, threshold_low, threshold_high, weak, strong
):
""" """
High-Low threshold detection. If an edge pixels gradient value is higher High-Low threshold detection. If an edge pixels gradient value is higher
than the high threshold value, it is marked as a strong edge pixel. If an than the high threshold value, it is marked as a strong edge pixel. If an
@ -80,43 +81,63 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255):
an edge pixel's value is smaller than the low threshold value, it will be an edge pixel's value is smaller than the low threshold value, it will be
suppressed. suppressed.
""" """
if dst[row, col] >= threshold_high: for row in range(1, image_shape[0] - 1):
dst[row, col] = strong for col in range(1, image_shape[1] - 1):
elif dst[row, col] <= threshold_low: if destination[row, col] >= threshold_high:
dst[row, col] = 0 destination[row, col] = strong
elif destination[row, col] <= threshold_low:
destination[row, col] = 0
else: else:
dst[row, col] = weak destination[row, col] = weak
def track_edge(image_shape, destination, weak, strong):
""" """
Edge tracking. Usually a weak edge pixel caused from true edges will be connected Edge tracking. Usually a weak edge pixel caused from true edges will be connected
to a strong edge pixel while noise responses are unconnected. As long as there is to a strong edge pixel while noise responses are unconnected. As long as there is
one strong edge pixel that is involved in its 8-connected neighborhood, that weak one strong edge pixel that is involved in its 8-connected neighborhood, that weak
edge point can be identified as one that should be preserved. edge point can be identified as one that should be preserved.
""" """
for row in range(1, image_row): for row in range(1, image_shape[0]):
for col in range(1, image_col): for col in range(1, image_shape[1]):
if dst[row, col] == weak: if destination[row, col] == weak:
if 255 in ( if 255 in (
dst[row, col + 1], destination[row, col + 1],
dst[row, col - 1], destination[row, col - 1],
dst[row - 1, col], destination[row - 1, col],
dst[row + 1, col], destination[row + 1, col],
dst[row - 1, col - 1], destination[row - 1, col - 1],
dst[row + 1, col - 1], destination[row + 1, col - 1],
dst[row - 1, col + 1], destination[row - 1, col + 1],
dst[row + 1, col + 1], destination[row + 1, col + 1],
): ):
dst[row, col] = strong destination[row, col] = strong
else: else:
dst[row, col] = 0 destination[row, col] = 0
return dst
def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255):
# gaussian_filter
gaussian_out = img_convolve(image, gen_gaussian_kernel(9, sigma=1.4))
# get the gradient and degree by sobel_filter
sobel_grad, sobel_theta = sobel_filter(gaussian_out)
gradient_direction = PI + np.rad2deg(sobel_theta)
destination = suppress_non_maximum(image.shape, gradient_direction, sobel_grad)
detect_high_low_threshold(
image.shape, destination, threshold_low, threshold_high, weak, strong
)
track_edge(image.shape, destination, weak, strong)
return destination
if __name__ == "__main__": if __name__ == "__main__":
# read original image in gray mode # read original image in gray mode
lena = cv2.imread(r"../image_data/lena.jpg", 0) lena = cv2.imread(r"../image_data/lena.jpg", 0)
# canny edge detection # canny edge detection
canny_dst = canny(lena) canny_destination = canny(lena)
cv2.imshow("canny", canny_dst) cv2.imshow("canny", canny_destination)
cv2.waitKey(0) cv2.waitKey(0)

View File

@ -1,33 +1,35 @@
from pathlib import Path
import numpy as np import numpy as np
from PIL import Image from PIL import Image
def rgb2gray(rgb: np.array) -> np.array: def rgb_to_gray(rgb: np.ndarray) -> np.ndarray:
""" """
Return gray image from rgb image Return gray image from rgb image
>>> rgb2gray(np.array([[[127, 255, 0]]])) >>> rgb_to_gray(np.array([[[127, 255, 0]]]))
array([[187.6453]]) array([[187.6453]])
>>> rgb2gray(np.array([[[0, 0, 0]]])) >>> rgb_to_gray(np.array([[[0, 0, 0]]]))
array([[0.]]) array([[0.]])
>>> rgb2gray(np.array([[[2, 4, 1]]])) >>> rgb_to_gray(np.array([[[2, 4, 1]]]))
array([[3.0598]]) array([[3.0598]])
>>> rgb2gray(np.array([[[26, 255, 14], [5, 147, 20], [1, 200, 0]]])) >>> rgb_to_gray(np.array([[[26, 255, 14], [5, 147, 20], [1, 200, 0]]]))
array([[159.0524, 90.0635, 117.6989]]) array([[159.0524, 90.0635, 117.6989]])
""" """
r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2] r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
return 0.2989 * r + 0.5870 * g + 0.1140 * b return 0.2989 * r + 0.5870 * g + 0.1140 * b
def gray2binary(gray: np.array) -> np.array: def gray_to_binary(gray: np.ndarray) -> np.ndarray:
""" """
Return binary image from gray image Return binary image from gray image
>>> gray2binary(np.array([[127, 255, 0]])) >>> gray_to_binary(np.array([[127, 255, 0]]))
array([[False, True, False]]) array([[False, True, False]])
>>> gray2binary(np.array([[0]])) >>> gray_to_binary(np.array([[0]]))
array([[False]]) array([[False]])
>>> gray2binary(np.array([[26.2409, 4.9315, 1.4729]])) >>> gray_to_binary(np.array([[26.2409, 4.9315, 1.4729]]))
array([[False, False, False]]) array([[False, False, False]])
>>> gray2binary(np.array([[26, 255, 14], [5, 147, 20], [1, 200, 0]])) >>> gray_to_binary(np.array([[26, 255, 14], [5, 147, 20], [1, 200, 0]]))
array([[False, True, False], array([[False, True, False],
[False, True, False], [False, True, False],
[False, True, False]]) [False, True, False]])
@ -35,7 +37,7 @@ def gray2binary(gray: np.array) -> np.array:
return (gray > 127) & (gray <= 255) return (gray > 127) & (gray <= 255)
def dilation(image: np.array, kernel: np.array) -> np.array: def dilation(image: np.ndarray, kernel: np.ndarray) -> np.ndarray:
""" """
Return dilated image Return dilated image
>>> dilation(np.array([[True, False, True]]), np.array([[0, 1, 0]])) >>> dilation(np.array([[True, False, True]]), np.array([[0, 1, 0]]))
@ -61,14 +63,13 @@ def dilation(image: np.array, kernel: np.array) -> np.array:
return output return output
# kernel to be applied
structuring_element = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
if __name__ == "__main__": if __name__ == "__main__":
# read original image # read original image
image = np.array(Image.open(r"..\image_data\lena.jpg")) lena_path = Path(__file__).resolve().parent / "image_data" / "lena.jpg"
output = dilation(gray2binary(rgb2gray(image)), structuring_element) lena = np.array(Image.open(lena_path))
# kernel to be applied
structuring_element = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
output = dilation(gray_to_binary(rgb_to_gray(lena)), structuring_element)
# Save the output image # Save the output image
pil_img = Image.fromarray(output).convert("RGB") pil_img = Image.fromarray(output).convert("RGB")
pil_img.save("result_dilation.png") pil_img.save("result_dilation.png")

View File

@ -0,0 +1,53 @@
def max_product_subarray(numbers: list[int]) -> int:
"""
Returns the maximum product that can be obtained by multiplying a
contiguous subarray of the given integer list `nums`.
Example:
>>> max_product_subarray([2, 3, -2, 4])
6
>>> max_product_subarray((-2, 0, -1))
0
>>> max_product_subarray([2, 3, -2, 4, -1])
48
>>> max_product_subarray([-1])
-1
>>> max_product_subarray([0])
0
>>> max_product_subarray([])
0
>>> max_product_subarray("")
0
>>> max_product_subarray(None)
0
>>> max_product_subarray([2, 3, -2, 4.5, -1])
Traceback (most recent call last):
...
ValueError: numbers must be an iterable of integers
>>> max_product_subarray("ABC")
Traceback (most recent call last):
...
ValueError: numbers must be an iterable of integers
"""
if not numbers:
return 0
if not isinstance(numbers, (list, tuple)) or not all(
isinstance(number, int) for number in numbers
):
raise ValueError("numbers must be an iterable of integers")
max_till_now = min_till_now = max_prod = numbers[0]
for i in range(1, len(numbers)):
# update the maximum and minimum subarray products
number = numbers[i]
if number < 0:
max_till_now, min_till_now = min_till_now, max_till_now
max_till_now = max(number, max_till_now * number)
min_till_now = min(number, min_till_now * number)
# update the maximum product found till now
max_prod = max(max_prod, max_till_now)
return max_prod

View File

@ -1,8 +1,9 @@
if __name__ == "__main__": import socket
import socket # Import socket module
sock = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 12312 port = 12312
sock.connect((host, port)) sock.connect((host, port))
@ -13,11 +14,14 @@ if __name__ == "__main__":
print("Receiving data...") print("Receiving data...")
while True: while True:
data = sock.recv(1024) data = sock.recv(1024)
print(f"{data = }")
if not data: if not data:
break break
out_file.write(data) # Write data to a file out_file.write(data)
print("Successfully got the file") print("Successfully received the file")
sock.close() sock.close()
print("Connection closed") print("Connection closed")
if __name__ == "__main__":
main()

View File

@ -17,6 +17,32 @@ from typing import Any
import numpy as np import numpy as np
def pass_and_relaxation(
graph: dict,
v: str,
visited_forward: set,
visited_backward: set,
cst_fwd: dict,
cst_bwd: dict,
queue: PriorityQueue,
parent: dict,
shortest_distance: float | int,
) -> float | int:
for nxt, d in graph[v]:
if nxt in visited_forward:
continue
old_cost_f = cst_fwd.get(nxt, np.inf)
new_cost_f = cst_fwd[v] + d
if new_cost_f < old_cost_f:
queue.put((new_cost_f, nxt))
cst_fwd[nxt] = new_cost_f
parent[nxt] = v
if nxt in visited_backward:
if cst_fwd[v] + d + cst_bwd[nxt] < shortest_distance:
shortest_distance = cst_fwd[v] + d + cst_bwd[nxt]
return shortest_distance
def bidirectional_dij( def bidirectional_dij(
source: str, destination: str, graph_forward: dict, graph_backward: dict source: str, destination: str, graph_forward: dict, graph_backward: dict
) -> int: ) -> int:
@ -51,53 +77,36 @@ def bidirectional_dij(
if source == destination: if source == destination:
return 0 return 0
while queue_forward and queue_backward: while not queue_forward.empty() and not queue_backward.empty():
while not queue_forward.empty():
_, v_fwd = queue_forward.get() _, v_fwd = queue_forward.get()
if v_fwd not in visited_forward:
break
else:
break
visited_forward.add(v_fwd) visited_forward.add(v_fwd)
while not queue_backward.empty():
_, v_bwd = queue_backward.get() _, v_bwd = queue_backward.get()
if v_bwd not in visited_backward:
break
else:
break
visited_backward.add(v_bwd) visited_backward.add(v_bwd)
# forward pass and relaxation shortest_distance = pass_and_relaxation(
for nxt_fwd, d_forward in graph_forward[v_fwd]: graph_forward,
if nxt_fwd in visited_forward: v_fwd,
continue visited_forward,
old_cost_f = cst_fwd.get(nxt_fwd, np.inf) visited_backward,
new_cost_f = cst_fwd[v_fwd] + d_forward cst_fwd,
if new_cost_f < old_cost_f: cst_bwd,
queue_forward.put((new_cost_f, nxt_fwd)) queue_forward,
cst_fwd[nxt_fwd] = new_cost_f parent_forward,
parent_forward[nxt_fwd] = v_fwd shortest_distance,
if nxt_fwd in visited_backward: )
if cst_fwd[v_fwd] + d_forward + cst_bwd[nxt_fwd] < shortest_distance:
shortest_distance = cst_fwd[v_fwd] + d_forward + cst_bwd[nxt_fwd]
# backward pass and relaxation shortest_distance = pass_and_relaxation(
for nxt_bwd, d_backward in graph_backward[v_bwd]: graph_backward,
if nxt_bwd in visited_backward: v_bwd,
continue visited_backward,
old_cost_b = cst_bwd.get(nxt_bwd, np.inf) visited_forward,
new_cost_b = cst_bwd[v_bwd] + d_backward cst_bwd,
if new_cost_b < old_cost_b: cst_fwd,
queue_backward.put((new_cost_b, nxt_bwd)) queue_backward,
cst_bwd[nxt_bwd] = new_cost_b parent_backward,
parent_backward[nxt_bwd] = v_bwd shortest_distance,
)
if nxt_bwd in visited_forward:
if cst_bwd[v_bwd] + d_backward + cst_fwd[nxt_bwd] < shortest_distance:
shortest_distance = cst_bwd[v_bwd] + d_backward + cst_fwd[nxt_bwd]
if cst_fwd[v_fwd] + cst_bwd[v_bwd] >= shortest_distance: if cst_fwd[v_fwd] + cst_bwd[v_bwd] >= shortest_distance:
break break

208
physics/grahams_law.py Normal file
View File

@ -0,0 +1,208 @@
"""
Title: Graham's Law of Effusion
Description: Graham's law of effusion states that the rate of effusion of a gas is
inversely proportional to the square root of the molar mass of its particles:
r1/r2 = sqrt(m2/m1)
r1 = Rate of effusion for the first gas.
r2 = Rate of effusion for the second gas.
m1 = Molar mass of the first gas.
m2 = Molar mass of the second gas.
(Description adapted from https://en.wikipedia.org/wiki/Graham%27s_law)
"""
from math import pow, sqrt
def validate(*values: float) -> bool:
"""
Input Parameters:
-----------------
effusion_rate_1: Effustion rate of first gas (m^2/s, mm^2/s, etc.)
effusion_rate_2: Effustion rate of second gas (m^2/s, mm^2/s, etc.)
molar_mass_1: Molar mass of the first gas (g/mol, kg/kmol, etc.)
molar_mass_2: Molar mass of the second gas (g/mol, kg/kmol, etc.)
Returns:
--------
>>> validate(2.016, 4.002)
True
>>> validate(-2.016, 4.002)
False
>>> validate()
False
"""
result = len(values) > 0 and all(value > 0.0 for value in values)
return result
def effusion_ratio(molar_mass_1: float, molar_mass_2: float) -> float | ValueError:
"""
Input Parameters:
-----------------
molar_mass_1: Molar mass of the first gas (g/mol, kg/kmol, etc.)
molar_mass_2: Molar mass of the second gas (g/mol, kg/kmol, etc.)
Returns:
--------
>>> effusion_ratio(2.016, 4.002)
1.408943
>>> effusion_ratio(-2.016, 4.002)
ValueError('Input Error: Molar mass values must greater than 0.')
>>> effusion_ratio(2.016)
Traceback (most recent call last):
...
TypeError: effusion_ratio() missing 1 required positional argument: 'molar_mass_2'
"""
return (
round(sqrt(molar_mass_2 / molar_mass_1), 6)
if validate(molar_mass_1, molar_mass_2)
else ValueError("Input Error: Molar mass values must greater than 0.")
)
def first_effusion_rate(
effusion_rate: float, molar_mass_1: float, molar_mass_2: float
) -> float | ValueError:
"""
Input Parameters:
-----------------
effusion_rate: Effustion rate of second gas (m^2/s, mm^2/s, etc.)
molar_mass_1: Molar mass of the first gas (g/mol, kg/kmol, etc.)
molar_mass_2: Molar mass of the second gas (g/mol, kg/kmol, etc.)
Returns:
--------
>>> first_effusion_rate(1, 2.016, 4.002)
1.408943
>>> first_effusion_rate(-1, 2.016, 4.002)
ValueError('Input Error: Molar mass and effusion rate values must greater than 0.')
>>> first_effusion_rate(1)
Traceback (most recent call last):
...
TypeError: first_effusion_rate() missing 2 required positional arguments: \
'molar_mass_1' and 'molar_mass_2'
>>> first_effusion_rate(1, 2.016)
Traceback (most recent call last):
...
TypeError: first_effusion_rate() missing 1 required positional argument: \
'molar_mass_2'
"""
return (
round(effusion_rate * sqrt(molar_mass_2 / molar_mass_1), 6)
if validate(effusion_rate, molar_mass_1, molar_mass_2)
else ValueError(
"Input Error: Molar mass and effusion rate values must greater than 0."
)
)
def second_effusion_rate(
effusion_rate: float, molar_mass_1: float, molar_mass_2: float
) -> float | ValueError:
"""
Input Parameters:
-----------------
effusion_rate: Effustion rate of second gas (m^2/s, mm^2/s, etc.)
molar_mass_1: Molar mass of the first gas (g/mol, kg/kmol, etc.)
molar_mass_2: Molar mass of the second gas (g/mol, kg/kmol, etc.)
Returns:
--------
>>> second_effusion_rate(1, 2.016, 4.002)
0.709752
>>> second_effusion_rate(-1, 2.016, 4.002)
ValueError('Input Error: Molar mass and effusion rate values must greater than 0.')
>>> second_effusion_rate(1)
Traceback (most recent call last):
...
TypeError: second_effusion_rate() missing 2 required positional arguments: \
'molar_mass_1' and 'molar_mass_2'
>>> second_effusion_rate(1, 2.016)
Traceback (most recent call last):
...
TypeError: second_effusion_rate() missing 1 required positional argument: \
'molar_mass_2'
"""
return (
round(effusion_rate / sqrt(molar_mass_2 / molar_mass_1), 6)
if validate(effusion_rate, molar_mass_1, molar_mass_2)
else ValueError(
"Input Error: Molar mass and effusion rate values must greater than 0."
)
)
def first_molar_mass(
molar_mass: float, effusion_rate_1: float, effusion_rate_2: float
) -> float | ValueError:
"""
Input Parameters:
-----------------
molar_mass: Molar mass of the first gas (g/mol, kg/kmol, etc.)
effusion_rate_1: Effustion rate of first gas (m^2/s, mm^2/s, etc.)
effusion_rate_2: Effustion rate of second gas (m^2/s, mm^2/s, etc.)
Returns:
--------
>>> first_molar_mass(2, 1.408943, 0.709752)
0.507524
>>> first_molar_mass(-1, 2.016, 4.002)
ValueError('Input Error: Molar mass and effusion rate values must greater than 0.')
>>> first_molar_mass(1)
Traceback (most recent call last):
...
TypeError: first_molar_mass() missing 2 required positional arguments: \
'effusion_rate_1' and 'effusion_rate_2'
>>> first_molar_mass(1, 2.016)
Traceback (most recent call last):
...
TypeError: first_molar_mass() missing 1 required positional argument: \
'effusion_rate_2'
"""
return (
round(molar_mass / pow(effusion_rate_1 / effusion_rate_2, 2), 6)
if validate(molar_mass, effusion_rate_1, effusion_rate_2)
else ValueError(
"Input Error: Molar mass and effusion rate values must greater than 0."
)
)
def second_molar_mass(
molar_mass: float, effusion_rate_1: float, effusion_rate_2: float
) -> float | ValueError:
"""
Input Parameters:
-----------------
molar_mass: Molar mass of the first gas (g/mol, kg/kmol, etc.)
effusion_rate_1: Effustion rate of first gas (m^2/s, mm^2/s, etc.)
effusion_rate_2: Effustion rate of second gas (m^2/s, mm^2/s, etc.)
Returns:
--------
>>> second_molar_mass(2, 1.408943, 0.709752)
1.970351
>>> second_molar_mass(-2, 1.408943, 0.709752)
ValueError('Input Error: Molar mass and effusion rate values must greater than 0.')
>>> second_molar_mass(1)
Traceback (most recent call last):
...
TypeError: second_molar_mass() missing 2 required positional arguments: \
'effusion_rate_1' and 'effusion_rate_2'
>>> second_molar_mass(1, 2.016)
Traceback (most recent call last):
...
TypeError: second_molar_mass() missing 1 required positional argument: \
'effusion_rate_2'
"""
return (
round(pow(effusion_rate_1 / effusion_rate_2, 2) / molar_mass, 6)
if validate(molar_mass, effusion_rate_1, effusion_rate_2)
else ValueError(
"Input Error: Molar mass and effusion rate values must greater than 0."
)
)

View File

@ -10,7 +10,7 @@ The solutions will be checked by our [automated testing on GitHub Actions](https
## Solution Guidelines ## Solution Guidelines
Welcome to [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python)! Before reading the solution guidelines, make sure you read the whole [Contributing Guidelines](https://github.com/TheAlgorithms/Python/blob/master/CONTRIBUTING.md) as it won't be repeated in here. If you have any doubt on the guidelines, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Python/issues/new) or ask the community in [Gitter](https://app.gitter.im/#/room/#TheAlgorithms_community:gitter.im). You can use the [template](https://github.com/TheAlgorithms/Python/blob/master/project_euler/README.md#solution-template) we have provided below as your starting point but be sure to read the [Coding Style](https://github.com/TheAlgorithms/Python/blob/master/project_euler/README.md#coding-style) part first. Welcome to [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python)! Before reading the solution guidelines, make sure you read the whole [Contributing Guidelines](https://github.com/TheAlgorithms/Python/blob/master/CONTRIBUTING.md) as it won't be repeated in here. If you have any doubt on the guidelines, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Python/issues/new) or ask the community in [Gitter](https://gitter.im/TheAlgorithms/community). You can use the [template](https://github.com/TheAlgorithms/Python/blob/master/project_euler/README.md#solution-template) we have provided below as your starting point but be sure to read the [Coding Style](https://github.com/TheAlgorithms/Python/blob/master/project_euler/README.md#coding-style) part first.
### Coding Style ### Coding Style

View File

View File

@ -0,0 +1,44 @@
"""
Project Euler Problem 94: https://projecteuler.net/problem=94
It is easily proved that no equilateral triangle exists with integral length sides and
integral area. However, the almost equilateral triangle 5-5-6 has an area of 12 square
units.
We shall define an almost equilateral triangle to be a triangle for which two sides are
equal and the third differs by no more than one unit.
Find the sum of the perimeters of all almost equilateral triangles with integral side
lengths and area and whose perimeters do not exceed one billion (1,000,000,000).
"""
def solution(max_perimeter: int = 10**9) -> int:
"""
Returns the sum of the perimeters of all almost equilateral triangles with integral
side lengths and area and whose perimeters do not exceed max_perimeter
>>> solution(20)
16
"""
prev_value = 1
value = 2
perimeters_sum = 0
i = 0
perimeter = 0
while perimeter <= max_perimeter:
perimeters_sum += perimeter
prev_value += 2 * value
value += prev_value
perimeter = 2 * value + 2 if i % 2 == 0 else 2 * value - 2
i += 1
return perimeters_sum
if __name__ == "__main__":
print(f"{solution() = }")

View File

View File

@ -0,0 +1,58 @@
"""
Project Euler Problem 187: https://projecteuler.net/problem=187
A composite is a number containing at least two prime factors.
For example, 15 = 3 x 5; 9 = 3 x 3; 12 = 2 x 2 x 3.
There are ten composites below thirty containing precisely two,
not necessarily distinct, prime factors: 4, 6, 9, 10, 14, 15, 21, 22, 25, 26.
How many composite integers, n < 10^8, have precisely two,
not necessarily distinct, prime factors?
"""
from math import isqrt
def calculate_prime_numbers(max_number: int) -> list[int]:
"""
Returns prime numbers below max_number
>>> calculate_prime_numbers(10)
[2, 3, 5, 7]
"""
is_prime = [True] * max_number
for i in range(2, isqrt(max_number - 1) + 1):
if is_prime[i]:
for j in range(i**2, max_number, i):
is_prime[j] = False
return [i for i in range(2, max_number) if is_prime[i]]
def solution(max_number: int = 10**8) -> int:
"""
Returns the number of composite integers below max_number have precisely two,
not necessarily distinct, prime factors
>>> solution(30)
10
"""
prime_numbers = calculate_prime_numbers(max_number // 2)
semiprimes_count = 0
left = 0
right = len(prime_numbers) - 1
while left <= right:
while prime_numbers[left] * prime_numbers[right] >= max_number:
right -= 1
semiprimes_count += right - left + 1
left += 1
return semiprimes_count
if __name__ == "__main__":
print(f"{solution() = }")

View File

View File

@ -0,0 +1,65 @@
"""
Project Euler Problem 800: https://projecteuler.net/problem=800
An integer of the form p^q q^p with prime numbers p != q is called a hybrid-integer.
For example, 800 = 2^5 5^2 is a hybrid-integer.
We define C(n) to be the number of hybrid-integers less than or equal to n.
You are given C(800) = 2 and C(800^800) = 10790
Find C(800800^800800)
"""
from math import isqrt, log2
def calculate_prime_numbers(max_number: int) -> list[int]:
"""
Returns prime numbers below max_number
>>> calculate_prime_numbers(10)
[2, 3, 5, 7]
"""
is_prime = [True] * max_number
for i in range(2, isqrt(max_number - 1) + 1):
if is_prime[i]:
for j in range(i**2, max_number, i):
is_prime[j] = False
return [i for i in range(2, max_number) if is_prime[i]]
def solution(base: int = 800800, degree: int = 800800) -> int:
"""
Returns the number of hybrid-integers less than or equal to base^degree
>>> solution(800, 1)
2
>>> solution(800, 800)
10790
"""
upper_bound = degree * log2(base)
max_prime = int(upper_bound)
prime_numbers = calculate_prime_numbers(max_prime)
hybrid_integers_count = 0
left = 0
right = len(prime_numbers) - 1
while left < right:
while (
prime_numbers[right] * log2(prime_numbers[left])
+ prime_numbers[left] * log2(prime_numbers[right])
> upper_bound
):
right -= 1
hybrid_integers_count += right - left
left += 1
return hybrid_integers_count
if __name__ == "__main__":
print(f"{solution() = }")

View File

@ -61,7 +61,7 @@ show-source = true
target-version = "py311" target-version = "py311"
[tool.ruff.mccabe] # DO NOT INCREASE THIS VALUE [tool.ruff.mccabe] # DO NOT INCREASE THIS VALUE
max-complexity = 20 # default: 10 max-complexity = 17 # default: 10
[tool.ruff.pylint] # DO NOT INCREASE THESE VALUES [tool.ruff.pylint] # DO NOT INCREASE THESE VALUES
max-args = 10 # default: 5 max-args = 10 # default: 5

View File

@ -723,5 +723,112 @@
"722": "9687101dfe209fd65f57a10603baa38ba83c9152e43a8b802b96f1e07f568e0e", "722": "9687101dfe209fd65f57a10603baa38ba83c9152e43a8b802b96f1e07f568e0e",
"723": "74832787e7d4e0cb7991256c8f6d02775dffec0684de234786f25f898003f2de", "723": "74832787e7d4e0cb7991256c8f6d02775dffec0684de234786f25f898003f2de",
"724": "fa05e2b497e7eafa64574017a4c45aadef6b163d907b03d63ba3f4021096d329", "724": "fa05e2b497e7eafa64574017a4c45aadef6b163d907b03d63ba3f4021096d329",
"725": "005c873563f51bbebfdb1f8dbc383259e9a98e506bc87ae8d8c9044b81fc6418" "725": "005c873563f51bbebfdb1f8dbc383259e9a98e506bc87ae8d8c9044b81fc6418",
"726": "93e41c533136bf4b436e493090fd4e7b277234db2a69c62a871f775ff26681bf",
"727": "c366f7426ca9351dcdde2e3bea01181897cda4d9b44977678ea3828419b84851",
"728": "8de62a644511d27c7c23c7722f56112b3c1ab9b05a078a98a0891f09f92464c6",
"729": "0ae82177174eef99fc80a2ec921295f61a6ac4dfed86a1bf333a50c26d01955c",
"730": "78cd876a176c8fbf7c2155b80dccbdededdbc43c28ef17b5a6e554d649325d38",
"731": "54afb9f829be51d29f90eecbfe40e5ba91f3a3bf538de62f3e34674af15eb542",
"732": "c4dc4610dcafc806b30e5d3f5560b57f462218a04397809843a7110838f0ebac",
"733": "bdde7d98d057d6a6ae360fd2f872d8bccb7e7f2971df37a3c5f20712ea3c618f",
"734": "9a514875bd9af26fcc565337771f852d311cd77033186e4d957e7b6c7b8ce018",
"735": "8bbc5a27c0031d8c44f3f73c99622a202cd6ea9a080049d615a7ae80ce6024f9",
"736": "e0d4c78b9b3dae51940877aff28275d036eccfc641111c8e34227ff6015a0fab",
"737": "a600884bcaa01797310c83b198bad58c98530289305af29b0bf75f679af38d3a",
"738": "c85f15fdaafe7d5525acff960afef7e4b8ffded5a7ee0d1dc2b0e8d0c26b9b46",
"739": "8716e9302f0fb90153e2f522bd88a710361a897480e4ccc0542473c704793518",
"740": "6ff41ee34b263b742cda109aee3be9ad6c95eec2ce31d6a9fc5353bba1b41afd",
"741": "99ac0eb9589b895e5755895206bbad5febd6bc29b2912df1c7544c547e26bca3",
"742": "7d2761a240aa577348df4813ea248088d0d6d8d421142c712ed576cdc90d4df9",
"743": "d93c42a129c0961b4e36738efae3b7e8ffae3a4daeced20e85bb740d3d72522d",
"744": "211f76700a010461486dde6c723720be85e68c192cd8a8ed0a88860b8ae9b0f0",
"745": "2d32dc1fea2f1b8600c0ada927b057b566870ceb5362cce71ac3693dcb7136ae",
"746": "2df1c2a0181f0c25e8d13d2a1eadba55a6b06267a2b22075fcf6867fb2e10c02",
"747": "a8d8f93142e320c6f0dd386c7a3bfb011bbdc15b85291a9be8f0266b3608175e",
"748": "7de937e04c10386b240afb8bb2ff590009946df8b7850a0329ccdb59fca8955f",
"749": "1a55f5484ccf964aeb186faedefa01db05d87180891dc2280b6eb85b6efb4779",
"750": "fa4318c213179e6af1c949be7cf47210f4383e0a44d191e2bad44228d3192f14",
"751": "12fe650fcb3afc214b3d647c655070e8142cfd397441fc7636ad7e6ffcaefde2",
"752": "e416c0123bc6b82df8726b328494db31aa4781d938a0a6e2107b1e44c73c0434",
"753": "0ee3299bc89e1e4c2fc79285fb1cd84c887456358a825e56be92244b7115f5af",
"754": "1370574b16207c41d3dafb62aa898379ec101ac36843634b1633b7b509d4c35a",
"755": "78bb4b18b13f5254cfafe872c0e93791ab5206b2851960dc6aebea8f62b9580c",
"756": "6becaabbda2e9ea22373e62e989b6b70467efa24fbe2f0d124d7a99a53e93f74",
"757": "fbfee0a5c4fa57a1dd6cf0c9bb2423cf7e7bcb130e67114aa360e42234987314",
"758": "8e4dfc259cec9dfd89d4b4ac8c33c75af6e0f5f7926526ee22ad4d45f93d3c18",
"759": "40bac0ed2e4f7861a6d9a2d87191a9034e177c319aa40a43638cc1b69572e5f2",
"760": "7ab50386a211f0815593389ab05b57a1a5eb5cbf5b9a85fe4afc517dcab74e06",
"761": "1cdb0318ac16e11c8d2ae7b1d7ca7138f7b1a461e9d75bd69be0f9cdd3add0c5",
"762": "84c4662267d5809380a540dfc2881665b3019047d74d5ef0a01f86e45f4b5b59",
"763": "f0def5903139447fabe7d106db5fff660d94b45af7b8b48d789596cf65ab2514",
"764": "7b4131f4d1e13d091ca7dd4d32317a14a2a24e6e1abd214df1c14c215287b330",
"765": "7558b775727426bccd945f5aa6b3e131e6034a7b1ff8576332329ef65d6a1663",
"766": "23c309430fa9546adb617457dbfd30fb7432904595c8c000e9b67ea23f32a53b",
"767": "70aef22ac2db8a5bdfcc42ff8dafbd2901e85e268f5f3c45085aa40c590b1d42",
"768": "b69a808dfc654b037e2f47ace16f48fe3bb553b3c8eed3e2b6421942fbf521d0",
"769": "78537a30577e806c6d8d94725e54d2d52e56f7f39f89c133cd5d0a2aad7e46e4",
"770": "c9d80c19c4895d1498bf809fcc37c447fa961fb325e5667eb35d6aa992966b41",
"771": "9803ace30c0d90d422e703fdf25a10a9342d0178a277ebc20c7bd6feac4c7a15",
"772": "f5a1e391af815ea6453db58a1bd71790f433c44ed63e5e93d8f5c045dfd5a464",
"773": "e1b93fc323c4d9c383100603339548e1e56ce9c38bcdcc425024c12b862ea8cb",
"774": "3646cd098b213014fb7bbc9597871585e62ee0cf2770e141f1df771237cc09ab",
"775": "d9d7d515ce7350c9e5696d85f68bbb42daa74b9e171a601dd04c823b18bb7757",
"776": "83286074d3bc86a5b449facb5fe5eafc91eb4c8031e2fb5e716443402cd8ed0f",
"777": "e62616a387d05b619d47cee3d49d5d2db19393736bf54b6cdd20933c0531cb7e",
"778": "d4de958ba44d25353de5b380e04d06c7968794ad50dbf6231ad0049ff53e106b",
"779": "c08ce54a59afc4af62f28b80a9c9a5190822d124eed8d73fd6db3e19c81e2157",
"780": "fc7ba646c16482f0f4f5ce2b06d21183dba2bdeaf9469b36b55bc7bc2d87baf3",
"781": "8fa5733f06838fb61b55b3e9d59c5061d922147e59947fe52e566dd975b2199f",
"782": "9f757d92df401ee049bc066bb2625c6287e5e4bcd38c958396a77a578f036a24",
"783": "270ff37f60c267a673bd4b223e44941f01ae9cfbf6bbdf99ca57af89b1e9a66f",
"784": "388b17c4c7b829cef767f83b4686c903faeec1241edfe5f58ee91d2b0c7f8dfc",
"785": "77cf600204c5265e1d5d3d26bf28ba1e92e6f24def040c16977450bec8b1cb99",
"786": "fb14022b7edbc6c7bfde27f35b49f6acaa4f0fc383af27614cb9d4a1980e626b",
"787": "7516ba0ac1951665723dcc4adcc52764d9497e7b6ed30bdb9937ac9df82b7c4f",
"788": "adede1d30258bb0f353af11f559b67f8b823304c71e967f52db52d002760c24f",
"789": "0c82e744a1f9bc57fd8ae8b2f479998455bc45126de971c59b68541c254e303a",
"790": "319847122251afd20d4d650047c55981a509fa2be78abd7c9c3caa0555e60a05",
"791": "2e0bbdcd0a8460e1e33c55668d0dc9752379a78b9f3561d7a17b922a5541a3fb",
"792": "5f77834c5a509023dd95dd98411eae1dd4bafd125deca590632f409f92fd257b",
"793": "dbfd900a3b31eeec2f14b916f5151611541cb716d80b7b9a1229de12293a02ea",
"794": "d019fe415aba832c4c761140d60c466c9aaad52b504df3167c17f2d3f0b277a7",
"795": "617b259349da44c2af2664acde113673ab3bb03a85d31f1be8f01027d0ebd4d3",
"796": "cba6b30a818d073398e5802211987f0897523e4752987bb445b2bca079670e22",
"797": "61e42cac3d7858b8850111a8c64c56432a18dd058dfb6afd773f07d703703b1a",
"798": "ae8b155d6b77522af79f7e4017fefe92aaa5d45eff132c83dc4d4bcfc9686020",
"799": "a41cb14ddf8f1948a01f590fbe53d9ca4e2faf48375ce1c306f91acf7c94e005",
"800": "c6a47bc6f02cf06be16728fb308c83f2f2ae350325ef7016867f5bdaea849d71",
"801": "d14b358c76b55106613f9c0a2112393338dfd01513b0fd231b79fc8db20e41f0",
"802": "22ae33e67fb48accfaa3b36e70c5a19066b974194c3130680de0c7cdce2d0f2e",
"803": "d95b3f9bbb7054042c1fba4db02f7223a2dad94977a36f08c8aaf92f373f9e78",
"804": "b0b1cf7253593eb2334c75e66dbe22b4b4540347485f1ea24e80226b4b18171c",
"805": "41b1ff5db0e70984ad20c50d1a9ac2b5a53ccd5f42796c8e948ae8880005fbb9",
"806": "b9c813beb39671adb8e1530555cadca44c21ddc7127932274918df2091dbd9ca",
"807": "745fd9ba97970d85a29877942839e41fc192794420e86f3bde39fd26db7a8bff",
"808": "6c73b947eb603602a7e8afadc83eaaa381a46db8b82a6fb89c9c1d93cb023fce",
"809": "eebac7753da4c1230dfce0f15fc124ffff01b0e432f0b74623b60cff71bbc9a9",
"810": "42be7899672a1a0046823603ce60dbeda7250a56fcb8d0913093850c85394307",
"811": "8698cd28ae4d93db36631870c33e4a8a527d970050d994666115f54260b64138",
"812": "dc2495924f37353db8b846323b8085fae9db502e890c513ed2e64ed7281f567f",
"813": "92179dde05aa6557baca65699fda50ca024d33a77078d8e128caa3c5db84064b",
"814": "344ed8cb7684307c00b7f03d751729a7f9d2a5f4a4cb4574594113d69593c0c1",
"815": "f642cf15345af3feab60e26a02aee038f759914906a5b2b469b46fdeee50ff59",
"816": "058178444e85f2aedb2f75d824a469747381f0bd3235d8c72df4385fec86eb07",
"817": "582fdc2233298192b09ceaf1463d6be06a09894075532630aa9d9efcfcb31da4",
"818": "67f6964d6ff114a43371b8375c44db2f1362df4f110b4a7ce8d79cf1b76621a0",
"819": "c7a82513ad48dfc87f2c1e0f2915b71464b7f5a16501c71df4ae4a8741dceef3",
"820": "9b23ae0181f320aadda2637ac2179c8b41b00715630c3acb643c7aee3b81cf90",
"821": "0941e396ff15b98fd7827de8e33ef94996d48ba719a88ba8e2da7f2605df3e5c",
"822": "ed8ef7f568939b9df1b77ae58344940b91c7e154a4367fe2b179bc7b9484d4e6",
"823": "05139328571a86096032b57e3a6a02a61acad4fb0d8f8e1b5d0ffb0d063ba697",
"826": "7f40f14ca65e5c06dd9ec9bbb212adb4d97a503199cb3c30ed921a04373bbe1c",
"827": "80461f02c63654c642382a6ffb7a44d0a3554434dfcfcea00ba91537724c7106",
"828": "520c196175625a0230afb76579ea26033372de3ef4c78aceb146b84322bfa871",
"829": "ed0089e61cf5540dd4a8fef1c468b96cf57f1d2bb79968755ba856d547ddafdf",
"831": "8ec445084427419ca6da405e0ded9814a4b4e11a2be84d88a8dea421f8e49992",
"832": "cfcb9ebef9308823f64798b5e12a59bf77ff6f92b0eae3790a61c0a26f577010",
"833": "e6ff3a5b257eb53366a32bfc8ea410a00a78bafa63650c76ac2bceddfbb42ff5",
"834": "b0d2a7e7d629ef14db9e7352a9a06d6ca66f750429170bb169ca52c172b8cc96",
"835": "bdfa1b1eecbad79f5de48bc6daee4d2b07689d7fb172aa306dd6094172b396f0"
} }