Compare commits

...

5 Commits

Author SHA1 Message Date
Tianyi Zheng
33114f0272
Revamp md5.py (#8065)
* Add type hints to md5.py

* Rename some vars to snake case

* Specify functions imported from math

* Rename vars and functions to be more descriptive

* Make tests from test function into doctests

* Clarify more var names

* Refactor some MD5 code into preprocess function

* Simplify loop indices in get_block_words

* Add more detailed comments, docs, and doctests

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* Add type hints to md5.py

* Rename some vars to snake case

* Specify functions imported from math

* Rename vars and functions to be more descriptive

* Make tests from test function into doctests

* Clarify more var names

* Refactor some MD5 code into preprocess function

* Simplify loop indices in get_block_words

* Add more detailed comments, docs, and doctests

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* Convert str types to bytes

* Add tests comparing md5_me to hashlib's md5

* Replace line-break backslashes with parentheses

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
2023-04-01 22:05:01 +02:00
Maxim Smolskiy
56a40eb3ee
Reenable files when TensorFlow supports the current Python (#8602)
* Remove python_version < "3.11" for tensorflow

* Reenable neural_network/input_data.py_tf

* updating DIRECTORY.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Try to fix ruff

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Try to fix ruff

* Try to fix ruff

* Try to fix ruff

* Try to fix pre-commit

* Try to fix

* Fix

* Fix

* Reenable dynamic_programming/k_means_clustering_tensorflow.py_tf

* updating DIRECTORY.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Try to fix ruff

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-04-01 19:43:11 +02:00
Blake Reimer
84b6852de8
Graham's Law (#8162)
* grahams law

* doctest and type hints

* doctest formatting

* peer review updates
2023-04-01 18:43:07 +02:00
Tianyi Zheng
a213cea5f5
Fix mypy errors in dilation_operation.py (#8595)
* updating DIRECTORY.md

* Fix mypy errors in dilation_operation.py

* Rename functions to use snake case

* updating DIRECTORY.md

* updating DIRECTORY.md

* Replace raw file string with pathlib Path

* Update digital_image_processing/morphological_operations/dilation_operation.py

Co-authored-by: Christian Clauss <cclauss@me.com>

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
2023-04-01 18:39:22 +02:00
Maxim Smolskiy
59cae167e0
Reduce the complexity of digital_image_processing/edge detection/canny.py (#8167)
* Reduce the complexity of digital_image_processing/edge_detection/canny.py

* Fix

* updating DIRECTORY.md

* updating DIRECTORY.md

* updating DIRECTORY.md

* Fix review issues

* Rename dst to destination

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
2023-04-01 18:22:33 +02:00
8 changed files with 646 additions and 210 deletions

View File

@ -309,6 +309,7 @@
* [Floyd Warshall](dynamic_programming/floyd_warshall.py) * [Floyd Warshall](dynamic_programming/floyd_warshall.py)
* [Integer Partition](dynamic_programming/integer_partition.py) * [Integer Partition](dynamic_programming/integer_partition.py)
* [Iterating Through Submasks](dynamic_programming/iterating_through_submasks.py) * [Iterating Through Submasks](dynamic_programming/iterating_through_submasks.py)
* [K Means Clustering Tensorflow](dynamic_programming/k_means_clustering_tensorflow.py)
* [Knapsack](dynamic_programming/knapsack.py) * [Knapsack](dynamic_programming/knapsack.py)
* [Longest Common Subsequence](dynamic_programming/longest_common_subsequence.py) * [Longest Common Subsequence](dynamic_programming/longest_common_subsequence.py)
* [Longest Common Substring](dynamic_programming/longest_common_substring.py) * [Longest Common Substring](dynamic_programming/longest_common_substring.py)
@ -685,6 +686,7 @@
* [2 Hidden Layers Neural Network](neural_network/2_hidden_layers_neural_network.py) * [2 Hidden Layers Neural Network](neural_network/2_hidden_layers_neural_network.py)
* [Back Propagation Neural Network](neural_network/back_propagation_neural_network.py) * [Back Propagation Neural Network](neural_network/back_propagation_neural_network.py)
* [Convolution Neural Network](neural_network/convolution_neural_network.py) * [Convolution Neural Network](neural_network/convolution_neural_network.py)
* [Input Data](neural_network/input_data.py)
* [Perceptron](neural_network/perceptron.py) * [Perceptron](neural_network/perceptron.py)
* [Simple Neural Network](neural_network/simple_neural_network.py) * [Simple Neural Network](neural_network/simple_neural_network.py)
@ -715,6 +717,7 @@
* [Archimedes Principle](physics/archimedes_principle.py) * [Archimedes Principle](physics/archimedes_principle.py)
* [Casimir Effect](physics/casimir_effect.py) * [Casimir Effect](physics/casimir_effect.py)
* [Centripetal Force](physics/centripetal_force.py) * [Centripetal Force](physics/centripetal_force.py)
* [Grahams Law](physics/grahams_law.py)
* [Horizontal Projectile Motion](physics/horizontal_projectile_motion.py) * [Horizontal Projectile Motion](physics/horizontal_projectile_motion.py)
* [Hubble Parameter](physics/hubble_parameter.py) * [Hubble Parameter](physics/hubble_parameter.py)
* [Ideal Gas Law](physics/ideal_gas_law.py) * [Ideal Gas Law](physics/ideal_gas_law.py)

View File

@ -18,105 +18,126 @@ 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
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
edge pixels gradient value is smaller than the high threshold value and def detect_high_low_threshold(
larger than the low threshold value, it is marked as a weak edge pixel. If image_shape, destination, threshold_low, threshold_high, weak, strong
an edge pixel's value is smaller than the low threshold value, it will be ):
suppressed. """
""" High-Low threshold detection. If an edge pixels gradient value is higher
if dst[row, col] >= threshold_high: than the high threshold value, it is marked as a strong edge pixel. If an
dst[row, col] = strong edge pixels gradient value is smaller than the high threshold value and
elif dst[row, col] <= threshold_low: larger than the low threshold value, it is marked as a weak edge pixel. If
dst[row, col] = 0 an edge pixel's value is smaller than the low threshold value, it will be
suppressed.
"""
for row in range(1, image_shape[0] - 1):
for col in range(1, image_shape[1] - 1):
if destination[row, col] >= threshold_high:
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

@ -1,9 +1,10 @@
import tensorflow as tf
from random import shuffle from random import shuffle
import tensorflow as tf
from numpy import array from numpy import array
def TFKMeansCluster(vectors, noofclusters): def tf_k_means_cluster(vectors, noofclusters):
""" """
K-Means Clustering using TensorFlow. K-Means Clustering using TensorFlow.
'vectors' should be a n*k 2-D NumPy array, where n is the number 'vectors' should be a n*k 2-D NumPy array, where n is the number
@ -30,7 +31,6 @@ def TFKMeansCluster(vectors, noofclusters):
graph = tf.Graph() graph = tf.Graph()
with graph.as_default(): with graph.as_default():
# SESSION OF COMPUTATION # SESSION OF COMPUTATION
sess = tf.Session() sess = tf.Session()
@ -95,8 +95,7 @@ def TFKMeansCluster(vectors, noofclusters):
# iterations. To keep things simple, we will only do a set number of # iterations. To keep things simple, we will only do a set number of
# iterations, instead of using a Stopping Criterion. # iterations, instead of using a Stopping Criterion.
noofiterations = 100 noofiterations = 100
for iteration_n in range(noofiterations): for _ in range(noofiterations):
##EXPECTATION STEP ##EXPECTATION STEP
##Based on the centroid locations till last iteration, compute ##Based on the centroid locations till last iteration, compute
##the _expected_ centroid assignments. ##the _expected_ centroid assignments.

View File

@ -1,91 +1,223 @@
import math """
The MD5 algorithm is a hash function that's commonly used as a checksum to
detect data corruption. The algorithm works by processing a given message in
blocks of 512 bits, padding the message as needed. It uses the blocks to operate
a 128-bit state and performs a total of 64 such operations. Note that all values
are little-endian, so inputs are converted as needed.
Although MD5 was used as a cryptographic hash function in the past, it's since
been cracked, so it shouldn't be used for security purposes.
For more info, see https://en.wikipedia.org/wiki/MD5
"""
from collections.abc import Generator
from math import sin
def rearrange(bit_string_32): def to_little_endian(string_32: bytes) -> bytes:
"""[summary] """
Regroups the given binary string. Converts the given string to little-endian in groups of 8 chars.
Arguments: Arguments:
bitString32 {[string]} -- [32 bit binary] string_32 {[string]} -- [32-char string]
Raises: Raises:
ValueError -- [if the given string not are 32 bit binary string] ValueError -- [input is not 32 char]
Returns: Returns:
[string] -- [32 bit binary string] 32-char little-endian string
>>> rearrange('1234567890abcdfghijklmnopqrstuvw') >>> to_little_endian(b'1234567890abcdfghijklmnopqrstuvw')
'pqrstuvwhijklmno90abcdfg12345678' b'pqrstuvwhijklmno90abcdfg12345678'
>>> to_little_endian(b'1234567890')
Traceback (most recent call last):
...
ValueError: Input must be of length 32
""" """
if len(string_32) != 32:
raise ValueError("Input must be of length 32")
if len(bit_string_32) != 32: little_endian = b""
raise ValueError("Need length 32")
new_string = ""
for i in [3, 2, 1, 0]: for i in [3, 2, 1, 0]:
new_string += bit_string_32[8 * i : 8 * i + 8] little_endian += string_32[8 * i : 8 * i + 8]
return new_string return little_endian
def reformat_hex(i): def reformat_hex(i: int) -> bytes:
"""[summary] """
Converts the given integer into 8-digit hex number. Converts the given non-negative integer to hex string.
Example: Suppose the input is the following:
i = 1234
The input is 0x000004d2 in hex, so the little-endian hex string is
"d2040000".
Arguments: Arguments:
i {[int]} -- [integer] i {[int]} -- [integer]
Raises:
ValueError -- [input is negative]
Returns:
8-char little-endian hex string
>>> reformat_hex(1234)
b'd2040000'
>>> reformat_hex(666) >>> reformat_hex(666)
'9a020000' b'9a020000'
>>> reformat_hex(0)
b'00000000'
>>> reformat_hex(1234567890)
b'd2029649'
>>> reformat_hex(1234567890987654321)
b'b11c6cb1'
>>> reformat_hex(-1)
Traceback (most recent call last):
...
ValueError: Input must be non-negative
""" """
if i < 0:
raise ValueError("Input must be non-negative")
hexrep = format(i, "08x") hex_rep = format(i, "08x")[-8:]
thing = "" little_endian_hex = b""
for i in [3, 2, 1, 0]: for i in [3, 2, 1, 0]:
thing += hexrep[2 * i : 2 * i + 2] little_endian_hex += hex_rep[2 * i : 2 * i + 2].encode("utf-8")
return thing return little_endian_hex
def pad(bit_string): def preprocess(message: bytes) -> bytes:
"""[summary] """
Fills up the binary string to a 512 bit binary string Preprocesses the message string:
- Convert message to bit string
- Pad bit string to a multiple of 512 chars:
- Append a 1
- Append 0's until length = 448 (mod 512)
- Append length of original message (64 chars)
Example: Suppose the input is the following:
message = "a"
The message bit string is "01100001", which is 8 bits long. Thus, the
bit string needs 439 bits of padding so that
(bit_string + "1" + padding) = 448 (mod 512).
The message length is "000010000...0" in 64-bit little-endian binary.
The combined bit string is then 512 bits long.
Arguments: Arguments:
bitString {[string]} -- [binary string] message {[string]} -- [message string]
Returns: Returns:
[string] -- [binary string] processed bit string padded to a multiple of 512 chars
>>> preprocess(b"a") == (b"01100001" + b"1" +
... (b"0" * 439) + b"00001000" + (b"0" * 56))
True
>>> preprocess(b"") == b"1" + (b"0" * 447) + (b"0" * 64)
True
""" """
start_length = len(bit_string) bit_string = b""
bit_string += "1" for char in message:
bit_string += format(char, "08b").encode("utf-8")
start_len = format(len(bit_string), "064b").encode("utf-8")
# Pad bit_string to a multiple of 512 chars
bit_string += b"1"
while len(bit_string) % 512 != 448: while len(bit_string) % 512 != 448:
bit_string += "0" bit_string += b"0"
last_part = format(start_length, "064b") bit_string += to_little_endian(start_len[32:]) + to_little_endian(start_len[:32])
bit_string += rearrange(last_part[32:]) + rearrange(last_part[:32])
return bit_string return bit_string
def get_block(bit_string): def get_block_words(bit_string: bytes) -> Generator[list[int], None, None]:
"""[summary] """
Iterator: Splits bit string into blocks of 512 chars and yields each block as a list
Returns by each call a list of length 16 with the 32 bit of 32-bit words
integer blocks.
Example: Suppose the input is the following:
bit_string =
"000000000...0" + # 0x00 (32 bits, padded to the right)
"000000010...0" + # 0x01 (32 bits, padded to the right)
"000000100...0" + # 0x02 (32 bits, padded to the right)
"000000110...0" + # 0x03 (32 bits, padded to the right)
...
"000011110...0" # 0x0a (32 bits, padded to the right)
Then len(bit_string) == 512, so there'll be 1 block. The block is split
into 32-bit words, and each word is converted to little endian. The
first word is interpreted as 0 in decimal, the second word is
interpreted as 1 in decimal, etc.
Thus, block_words == [[0, 1, 2, 3, ..., 15]].
Arguments: Arguments:
bit_string {[string]} -- [binary string >= 512] bit_string {[string]} -- [bit string with multiple of 512 as length]
Raises:
ValueError -- [length of bit string isn't multiple of 512]
Yields:
a list of 16 32-bit words
>>> test_string = ("".join(format(n << 24, "032b") for n in range(16))
... .encode("utf-8"))
>>> list(get_block_words(test_string))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
>>> list(get_block_words(test_string * 4)) == [list(range(16))] * 4
True
>>> list(get_block_words(b"1" * 512)) == [[4294967295] * 16]
True
>>> list(get_block_words(b""))
[]
>>> list(get_block_words(b"1111"))
Traceback (most recent call last):
...
ValueError: Input must have length that's a multiple of 512
""" """
if len(bit_string) % 512 != 0:
raise ValueError("Input must have length that's a multiple of 512")
curr_pos = 0 for pos in range(0, len(bit_string), 512):
while curr_pos < len(bit_string): block = bit_string[pos : pos + 512]
curr_part = bit_string[curr_pos : curr_pos + 512] block_words = []
my_splits = [] for i in range(0, 512, 32):
for i in range(16): block_words.append(int(to_little_endian(block[i : i + 32]), 2))
my_splits.append(int(rearrange(curr_part[32 * i : 32 * i + 32]), 2)) yield block_words
yield my_splits
curr_pos += 512
def not32(i): def not_32(i: int) -> int:
""" """
>>> not32(34) Perform bitwise NOT on given int.
Arguments:
i {[int]} -- [given int]
Raises:
ValueError -- [input is negative]
Returns:
Result of bitwise NOT on i
>>> not_32(34)
4294967261 4294967261
>>> not_32(1234)
4294966061
>>> not_32(4294966061)
1234
>>> not_32(0)
4294967295
>>> not_32(1)
4294967294
>>> not_32(-1)
Traceback (most recent call last):
...
ValueError: Input must be non-negative
""" """
if i < 0:
raise ValueError("Input must be non-negative")
i_str = format(i, "032b") i_str = format(i, "032b")
new_str = "" new_str = ""
for c in i_str: for c in i_str:
@ -93,35 +225,114 @@ def not32(i):
return int(new_str, 2) return int(new_str, 2)
def sum32(a, b): def sum_32(a: int, b: int) -> int:
"""
Add two numbers as 32-bit ints.
Arguments:
a {[int]} -- [first given int]
b {[int]} -- [second given int]
Returns:
(a + b) as an unsigned 32-bit int
>>> sum_32(1, 1)
2
>>> sum_32(2, 3)
5
>>> sum_32(0, 0)
0
>>> sum_32(-1, -1)
4294967294
>>> sum_32(4294967295, 1)
0
"""
return (a + b) % 2**32 return (a + b) % 2**32
def leftrot32(i, s): def left_rotate_32(i: int, shift: int) -> int:
return (i << s) ^ (i >> (32 - s)) """
Rotate the bits of a given int left by a given amount.
def md5me(test_string):
"""[summary]
Returns a 32-bit hash code of the string 'testString'
Arguments: Arguments:
testString {[string]} -- [message] i {[int]} -- [given int]
shift {[int]} -- [shift amount]
Raises:
ValueError -- [either given int or shift is negative]
Returns:
`i` rotated to the left by `shift` bits
>>> left_rotate_32(1234, 1)
2468
>>> left_rotate_32(1111, 4)
17776
>>> left_rotate_32(2147483648, 1)
1
>>> left_rotate_32(2147483648, 3)
4
>>> left_rotate_32(4294967295, 4)
4294967295
>>> left_rotate_32(1234, 0)
1234
>>> left_rotate_32(0, 0)
0
>>> left_rotate_32(-1, 0)
Traceback (most recent call last):
...
ValueError: Input must be non-negative
>>> left_rotate_32(0, -1)
Traceback (most recent call last):
...
ValueError: Shift must be non-negative
"""
if i < 0:
raise ValueError("Input must be non-negative")
if shift < 0:
raise ValueError("Shift must be non-negative")
return ((i << shift) ^ (i >> (32 - shift))) % 2**32
def md5_me(message: bytes) -> bytes:
"""
Returns the 32-char MD5 hash of a given message.
Reference: https://en.wikipedia.org/wiki/MD5#Algorithm
Arguments:
message {[string]} -- [message]
Returns:
32-char MD5 hash string
>>> md5_me(b"")
b'd41d8cd98f00b204e9800998ecf8427e'
>>> md5_me(b"The quick brown fox jumps over the lazy dog")
b'9e107d9d372bb6826bd81d3542a419d6'
>>> md5_me(b"The quick brown fox jumps over the lazy dog.")
b'e4d909c290d0fb1ca068ffaddf22cbd0'
>>> import hashlib
>>> from string import ascii_letters
>>> msgs = [b"", ascii_letters.encode("utf-8"), "Üñîçø∂é".encode("utf-8"),
... b"The quick brown fox jumps over the lazy dog."]
>>> all(md5_me(msg) == hashlib.md5(msg).hexdigest().encode("utf-8") for msg in msgs)
True
""" """
bs = "" # Convert to bit string, add padding and append message length
for i in test_string: bit_string = preprocess(message)
bs += format(ord(i), "08b")
bs = pad(bs)
tvals = [int(2**32 * abs(math.sin(i + 1))) for i in range(64)] added_consts = [int(2**32 * abs(sin(i + 1))) for i in range(64)]
# Starting states
a0 = 0x67452301 a0 = 0x67452301
b0 = 0xEFCDAB89 b0 = 0xEFCDAB89
c0 = 0x98BADCFE c0 = 0x98BADCFE
d0 = 0x10325476 d0 = 0x10325476
s = [ shift_amounts = [
7, 7,
12, 12,
17, 17,
@ -188,51 +399,46 @@ def md5me(test_string):
21, 21,
] ]
for m in get_block(bs): # Process bit string in chunks, each with 16 32-char words
for block_words in get_block_words(bit_string):
a = a0 a = a0
b = b0 b = b0
c = c0 c = c0
d = d0 d = d0
# Hash current chunk
for i in range(64): for i in range(64):
if i <= 15: if i <= 15:
# f = (B & C) | (not32(B) & D) # f = (b & c) | (not_32(b) & d) # Alternate definition for f
f = d ^ (b & (c ^ d)) f = d ^ (b & (c ^ d))
g = i g = i
elif i <= 31: elif i <= 31:
# f = (D & B) | (not32(D) & C) # f = (d & b) | (not_32(d) & c) # Alternate definition for f
f = c ^ (d & (b ^ c)) f = c ^ (d & (b ^ c))
g = (5 * i + 1) % 16 g = (5 * i + 1) % 16
elif i <= 47: elif i <= 47:
f = b ^ c ^ d f = b ^ c ^ d
g = (3 * i + 5) % 16 g = (3 * i + 5) % 16
else: else:
f = c ^ (b | not32(d)) f = c ^ (b | not_32(d))
g = (7 * i) % 16 g = (7 * i) % 16
dtemp = d f = (f + a + added_consts[i] + block_words[g]) % 2**32
a = d
d = c d = c
c = b c = b
b = sum32(b, leftrot32((a + f + tvals[i] + m[g]) % 2**32, s[i])) b = sum_32(b, left_rotate_32(f, shift_amounts[i]))
a = dtemp
a0 = sum32(a0, a) # Add hashed chunk to running total
b0 = sum32(b0, b) a0 = sum_32(a0, a)
c0 = sum32(c0, c) b0 = sum_32(b0, b)
d0 = sum32(d0, d) c0 = sum_32(c0, c)
d0 = sum_32(d0, d)
digest = reformat_hex(a0) + reformat_hex(b0) + reformat_hex(c0) + reformat_hex(d0) digest = reformat_hex(a0) + reformat_hex(b0) + reformat_hex(c0) + reformat_hex(d0)
return digest return digest
def test():
assert md5me("") == "d41d8cd98f00b204e9800998ecf8427e"
assert (
md5me("The quick brown fox jumps over the lazy dog")
== "9e107d9d372bb6826bd81d3542a419d6"
)
print("Success.")
if __name__ == "__main__": if __name__ == "__main__":
test()
import doctest import doctest
doctest.testmod() doctest.testmod()

View File

@ -21,13 +21,10 @@ This module and all its submodules are deprecated.
import collections import collections
import gzip import gzip
import os import os
import urllib
import numpy import numpy
from six.moves import urllib from tensorflow.python.framework import dtypes, random_seed
from six.moves import xrange # pylint: disable=redefined-builtin
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import random_seed
from tensorflow.python.platform import gfile from tensorflow.python.platform import gfile
from tensorflow.python.util.deprecation import deprecated from tensorflow.python.util.deprecation import deprecated
@ -46,16 +43,16 @@ def _read32(bytestream):
def _extract_images(f): def _extract_images(f):
"""Extract the images into a 4D uint8 numpy array [index, y, x, depth]. """Extract the images into a 4D uint8 numpy array [index, y, x, depth].
Args: Args:
f: A file object that can be passed into a gzip reader. f: A file object that can be passed into a gzip reader.
Returns: Returns:
data: A 4D uint8 numpy array [index, y, x, depth]. data: A 4D uint8 numpy array [index, y, x, depth].
Raises: Raises:
ValueError: If the bytestream does not start with 2051. ValueError: If the bytestream does not start with 2051.
""" """
print("Extracting", f.name) print("Extracting", f.name)
with gzip.GzipFile(fileobj=f) as bytestream: with gzip.GzipFile(fileobj=f) as bytestream:
magic = _read32(bytestream) magic = _read32(bytestream)
@ -86,17 +83,17 @@ def _dense_to_one_hot(labels_dense, num_classes):
def _extract_labels(f, one_hot=False, num_classes=10): def _extract_labels(f, one_hot=False, num_classes=10):
"""Extract the labels into a 1D uint8 numpy array [index]. """Extract the labels into a 1D uint8 numpy array [index].
Args: Args:
f: A file object that can be passed into a gzip reader. f: A file object that can be passed into a gzip reader.
one_hot: Does one hot encoding for the result. one_hot: Does one hot encoding for the result.
num_classes: Number of classes for the one hot encoding. num_classes: Number of classes for the one hot encoding.
Returns: Returns:
labels: a 1D uint8 numpy array. labels: a 1D uint8 numpy array.
Raises: Raises:
ValueError: If the bystream doesn't start with 2049. ValueError: If the bystream doesn't start with 2049.
""" """
print("Extracting", f.name) print("Extracting", f.name)
with gzip.GzipFile(fileobj=f) as bytestream: with gzip.GzipFile(fileobj=f) as bytestream:
magic = _read32(bytestream) magic = _read32(bytestream)
@ -115,8 +112,8 @@ def _extract_labels(f, one_hot=False, num_classes=10):
class _DataSet: class _DataSet:
"""Container class for a _DataSet (deprecated). """Container class for a _DataSet (deprecated).
THIS CLASS IS DEPRECATED. THIS CLASS IS DEPRECATED.
""" """
@deprecated( @deprecated(
None, None,
@ -135,21 +132,21 @@ class _DataSet:
): ):
"""Construct a _DataSet. """Construct a _DataSet.
one_hot arg is used only if fake_data is true. `dtype` can be either one_hot arg is used only if fake_data is true. `dtype` can be either
`uint8` to leave the input as `[0, 255]`, or `float32` to rescale into `uint8` to leave the input as `[0, 255]`, or `float32` to rescale into
`[0, 1]`. Seed arg provides for convenient deterministic testing. `[0, 1]`. Seed arg provides for convenient deterministic testing.
Args: Args:
images: The images images: The images
labels: The labels labels: The labels
fake_data: Ignore inages and labels, use fake data. fake_data: Ignore inages and labels, use fake data.
one_hot: Bool, return the labels as one hot vectors (if True) or ints (if one_hot: Bool, return the labels as one hot vectors (if True) or ints (if
False). False).
dtype: Output image dtype. One of [uint8, float32]. `uint8` output has dtype: Output image dtype. One of [uint8, float32]. `uint8` output has
range [0,255]. float32 output has range [0,1]. range [0,255]. float32 output has range [0,1].
reshape: Bool. If True returned images are returned flattened to vectors. reshape: Bool. If True returned images are returned flattened to vectors.
seed: The random seed to use. seed: The random seed to use.
""" """
seed1, seed2 = random_seed.get_seed(seed) seed1, seed2 = random_seed.get_seed(seed)
# If op level seed is not set, use whatever graph level seed is returned # If op level seed is not set, use whatever graph level seed is returned
numpy.random.seed(seed1 if seed is None else seed2) numpy.random.seed(seed1 if seed is None else seed2)
@ -206,8 +203,8 @@ class _DataSet:
else: else:
fake_label = 0 fake_label = 0
return ( return (
[fake_image for _ in xrange(batch_size)], [fake_image for _ in range(batch_size)],
[fake_label for _ in xrange(batch_size)], [fake_label for _ in range(batch_size)],
) )
start = self._index_in_epoch start = self._index_in_epoch
# Shuffle for the first epoch # Shuffle for the first epoch
@ -250,19 +247,19 @@ class _DataSet:
def _maybe_download(filename, work_directory, source_url): def _maybe_download(filename, work_directory, source_url):
"""Download the data from source url, unless it's already here. """Download the data from source url, unless it's already here.
Args: Args:
filename: string, name of the file in the directory. filename: string, name of the file in the directory.
work_directory: string, path to working directory. work_directory: string, path to working directory.
source_url: url to download from if file doesn't exist. source_url: url to download from if file doesn't exist.
Returns: Returns:
Path to resulting file. Path to resulting file.
""" """
if not gfile.Exists(work_directory): if not gfile.Exists(work_directory):
gfile.MakeDirs(work_directory) gfile.MakeDirs(work_directory)
filepath = os.path.join(work_directory, filename) filepath = os.path.join(work_directory, filename)
if not gfile.Exists(filepath): if not gfile.Exists(filepath):
urllib.request.urlretrieve(source_url, filepath) urllib.request.urlretrieve(source_url, filepath) # noqa: S310
with gfile.GFile(filepath) as f: with gfile.GFile(filepath) as f:
size = f.size() size = f.size()
print("Successfully downloaded", filename, size, "bytes.") print("Successfully downloaded", filename, size, "bytes.")
@ -328,7 +325,8 @@ def read_data_sets(
if not 0 <= validation_size <= len(train_images): if not 0 <= validation_size <= len(train_images):
raise ValueError( raise ValueError(
f"Validation size should be between 0 and {len(train_images)}. Received: {validation_size}." f"Validation size should be between 0 and {len(train_images)}. "
f"Received: {validation_size}."
) )
validation_images = train_images[:validation_size] validation_images = train_images[:validation_size]
@ -336,7 +334,7 @@ def read_data_sets(
train_images = train_images[validation_size:] train_images = train_images[validation_size:]
train_labels = train_labels[validation_size:] train_labels = train_labels[validation_size:]
options = dict(dtype=dtype, reshape=reshape, seed=seed) options = {"dtype": dtype, "reshape": reshape, "seed": seed}
train = _DataSet(train_images, train_labels, **options) train = _DataSet(train_images, train_labels, **options)
validation = _DataSet(validation_images, validation_labels, **options) validation = _DataSet(validation_images, validation_labels, **options)

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

@ -15,7 +15,7 @@ scikit-fuzzy
scikit-learn scikit-learn
statsmodels statsmodels
sympy sympy
tensorflow; python_version < "3.11" tensorflow
texttable texttable
tweepy tweepy
xgboost xgboost