Enable ruff ICN001 rule (#11329)

* Enable ruff ICN001 rule

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Maxim Smolskiy 2024-03-28 21:03:23 +03:00 committed by GitHub
parent efb7463cde
commit f2246ce7fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 121 additions and 128 deletions

View File

@ -38,7 +38,7 @@ https://www.youtube.com/watch?v=4RhLNDqcjpA
import string import string
import numpy import numpy as np
from maths.greatest_common_divisor import greatest_common_divisor from maths.greatest_common_divisor import greatest_common_divisor
@ -49,11 +49,11 @@ class HillCipher:
# i.e. a total of 36 characters # i.e. a total of 36 characters
# take x and return x % len(key_string) # take x and return x % len(key_string)
modulus = numpy.vectorize(lambda x: x % 36) modulus = np.vectorize(lambda x: x % 36)
to_int = numpy.vectorize(round) to_int = np.vectorize(round)
def __init__(self, encrypt_key: numpy.ndarray) -> None: def __init__(self, encrypt_key: np.ndarray) -> None:
""" """
encrypt_key is an NxN numpy array encrypt_key is an NxN numpy array
""" """
@ -63,7 +63,7 @@ class HillCipher:
def replace_letters(self, letter: str) -> int: def replace_letters(self, letter: str) -> int:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.replace_letters('T') >>> hill_cipher.replace_letters('T')
19 19
>>> hill_cipher.replace_letters('0') >>> hill_cipher.replace_letters('0')
@ -73,7 +73,7 @@ class HillCipher:
def replace_digits(self, num: int) -> str: def replace_digits(self, num: int) -> str:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.replace_digits(19) >>> hill_cipher.replace_digits(19)
'T' 'T'
>>> hill_cipher.replace_digits(26) >>> hill_cipher.replace_digits(26)
@ -83,10 +83,10 @@ class HillCipher:
def check_determinant(self) -> None: def check_determinant(self) -> None:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.check_determinant() >>> hill_cipher.check_determinant()
""" """
det = round(numpy.linalg.det(self.encrypt_key)) det = round(np.linalg.det(self.encrypt_key))
if det < 0: if det < 0:
det = det % len(self.key_string) det = det % len(self.key_string)
@ -101,7 +101,7 @@ class HillCipher:
def process_text(self, text: str) -> str: def process_text(self, text: str) -> str:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.process_text('Testing Hill Cipher') >>> hill_cipher.process_text('Testing Hill Cipher')
'TESTINGHILLCIPHERR' 'TESTINGHILLCIPHERR'
>>> hill_cipher.process_text('hello') >>> hill_cipher.process_text('hello')
@ -117,7 +117,7 @@ class HillCipher:
def encrypt(self, text: str) -> str: def encrypt(self, text: str) -> str:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.encrypt('testing hill cipher') >>> hill_cipher.encrypt('testing hill cipher')
'WHXYJOLM9C6XT085LL' 'WHXYJOLM9C6XT085LL'
>>> hill_cipher.encrypt('hello') >>> hill_cipher.encrypt('hello')
@ -129,7 +129,7 @@ class HillCipher:
for i in range(0, len(text) - self.break_key + 1, self.break_key): for i in range(0, len(text) - self.break_key + 1, self.break_key):
batch = text[i : i + self.break_key] batch = text[i : i + self.break_key]
vec = [self.replace_letters(char) for char in batch] vec = [self.replace_letters(char) for char in batch]
batch_vec = numpy.array([vec]).T batch_vec = np.array([vec]).T
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[ batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[
0 0
] ]
@ -140,14 +140,14 @@ class HillCipher:
return encrypted return encrypted
def make_decrypt_key(self) -> numpy.ndarray: def make_decrypt_key(self) -> np.ndarray:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.make_decrypt_key() >>> hill_cipher.make_decrypt_key()
array([[ 6, 25], array([[ 6, 25],
[ 5, 26]]) [ 5, 26]])
""" """
det = round(numpy.linalg.det(self.encrypt_key)) det = round(np.linalg.det(self.encrypt_key))
if det < 0: if det < 0:
det = det % len(self.key_string) det = det % len(self.key_string)
@ -158,16 +158,14 @@ class HillCipher:
break break
inv_key = ( inv_key = (
det_inv det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
* numpy.linalg.det(self.encrypt_key)
* numpy.linalg.inv(self.encrypt_key)
) )
return self.to_int(self.modulus(inv_key)) return self.to_int(self.modulus(inv_key))
def decrypt(self, text: str) -> str: def decrypt(self, text: str) -> str:
""" """
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
>>> hill_cipher.decrypt('WHXYJOLM9C6XT085LL') >>> hill_cipher.decrypt('WHXYJOLM9C6XT085LL')
'TESTINGHILLCIPHERR' 'TESTINGHILLCIPHERR'
>>> hill_cipher.decrypt('85FF00') >>> hill_cipher.decrypt('85FF00')
@ -180,7 +178,7 @@ class HillCipher:
for i in range(0, len(text) - self.break_key + 1, self.break_key): for i in range(0, len(text) - self.break_key + 1, self.break_key):
batch = text[i : i + self.break_key] batch = text[i : i + self.break_key]
vec = [self.replace_letters(char) for char in batch] vec = [self.replace_letters(char) for char in batch]
batch_vec = numpy.array([vec]).T batch_vec = np.array([vec]).T
batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0] batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0]
decrypted_batch = "".join( decrypted_batch = "".join(
self.replace_digits(num) for num in batch_decrypted self.replace_digits(num) for num in batch_decrypted
@ -199,7 +197,7 @@ def main() -> None:
row = [int(x) for x in input().split()] row = [int(x) for x in input().split()]
hill_matrix.append(row) hill_matrix.append(row)
hc = HillCipher(numpy.array(hill_matrix)) hc = HillCipher(np.array(hill_matrix))
print("Would you like to encrypt or decrypt some text? (1 or 2)") print("Would you like to encrypt or decrypt some text? (1 or 2)")
option = input("\n1. Encrypt\n2. Decrypt\n") option = input("\n1. Encrypt\n2. Decrypt\n")

View File

@ -25,8 +25,8 @@ import warnings
from collections.abc import Callable from collections.abc import Callable
from typing import Any from typing import Any
import numpy import matplotlib.pyplot as plt
from matplotlib import pyplot import numpy as np
c_cauliflower = 0.25 + 0.0j c_cauliflower = 0.25 + 0.0j
c_polynomial_1 = -0.4 + 0.6j c_polynomial_1 = -0.4 + 0.6j
@ -37,22 +37,20 @@ window_size = 2.0
nb_pixels = 666 nb_pixels = 666
def eval_exponential(c_parameter: complex, z_values: numpy.ndarray) -> numpy.ndarray: def eval_exponential(c_parameter: complex, z_values: np.ndarray) -> np.ndarray:
""" """
Evaluate $e^z + c$. Evaluate $e^z + c$.
>>> eval_exponential(0, 0) >>> eval_exponential(0, 0)
1.0 1.0
>>> abs(eval_exponential(1, numpy.pi*1.j)) < 1e-15 >>> abs(eval_exponential(1, np.pi*1.j)) < 1e-15
True True
>>> abs(eval_exponential(1.j, 0)-1-1.j) < 1e-15 >>> abs(eval_exponential(1.j, 0)-1-1.j) < 1e-15
True True
""" """
return numpy.exp(z_values) + c_parameter return np.exp(z_values) + c_parameter
def eval_quadratic_polynomial( def eval_quadratic_polynomial(c_parameter: complex, z_values: np.ndarray) -> np.ndarray:
c_parameter: complex, z_values: numpy.ndarray
) -> numpy.ndarray:
""" """
>>> eval_quadratic_polynomial(0, 2) >>> eval_quadratic_polynomial(0, 2)
4 4
@ -66,7 +64,7 @@ def eval_quadratic_polynomial(
return z_values * z_values + c_parameter return z_values * z_values + c_parameter
def prepare_grid(window_size: float, nb_pixels: int) -> numpy.ndarray: def prepare_grid(window_size: float, nb_pixels: int) -> np.ndarray:
""" """
Create a grid of complex values of size nb_pixels*nb_pixels with real and Create a grid of complex values of size nb_pixels*nb_pixels with real and
imaginary parts ranging from -window_size to window_size (inclusive). imaginary parts ranging from -window_size to window_size (inclusive).
@ -77,20 +75,20 @@ def prepare_grid(window_size: float, nb_pixels: int) -> numpy.ndarray:
[ 0.-1.j, 0.+0.j, 0.+1.j], [ 0.-1.j, 0.+0.j, 0.+1.j],
[ 1.-1.j, 1.+0.j, 1.+1.j]]) [ 1.-1.j, 1.+0.j, 1.+1.j]])
""" """
x = numpy.linspace(-window_size, window_size, nb_pixels) x = np.linspace(-window_size, window_size, nb_pixels)
x = x.reshape((nb_pixels, 1)) x = x.reshape((nb_pixels, 1))
y = numpy.linspace(-window_size, window_size, nb_pixels) y = np.linspace(-window_size, window_size, nb_pixels)
y = y.reshape((1, nb_pixels)) y = y.reshape((1, nb_pixels))
return x + 1.0j * y return x + 1.0j * y
def iterate_function( def iterate_function(
eval_function: Callable[[Any, numpy.ndarray], numpy.ndarray], eval_function: Callable[[Any, np.ndarray], np.ndarray],
function_params: Any, function_params: Any,
nb_iterations: int, nb_iterations: int,
z_0: numpy.ndarray, z_0: np.ndarray,
infinity: float | None = None, infinity: float | None = None,
) -> numpy.ndarray: ) -> np.ndarray:
""" """
Iterate the function "eval_function" exactly nb_iterations times. Iterate the function "eval_function" exactly nb_iterations times.
The first argument of the function is a parameter which is contained in The first argument of the function is a parameter which is contained in
@ -98,22 +96,22 @@ def iterate_function(
values to iterate from. values to iterate from.
This function returns the final iterates. This function returns the final iterates.
>>> iterate_function(eval_quadratic_polynomial, 0, 3, numpy.array([0,1,2])).shape >>> iterate_function(eval_quadratic_polynomial, 0, 3, np.array([0,1,2])).shape
(3,) (3,)
>>> numpy.round(iterate_function(eval_quadratic_polynomial, >>> np.round(iterate_function(eval_quadratic_polynomial,
... 0, ... 0,
... 3, ... 3,
... numpy.array([0,1,2]))[0]) ... np.array([0,1,2]))[0])
0j 0j
>>> numpy.round(iterate_function(eval_quadratic_polynomial, >>> np.round(iterate_function(eval_quadratic_polynomial,
... 0, ... 0,
... 3, ... 3,
... numpy.array([0,1,2]))[1]) ... np.array([0,1,2]))[1])
(1+0j) (1+0j)
>>> numpy.round(iterate_function(eval_quadratic_polynomial, >>> np.round(iterate_function(eval_quadratic_polynomial,
... 0, ... 0,
... 3, ... 3,
... numpy.array([0,1,2]))[2]) ... np.array([0,1,2]))[2])
(256+0j) (256+0j)
""" """
@ -121,8 +119,8 @@ def iterate_function(
for _ in range(nb_iterations): for _ in range(nb_iterations):
z_n = eval_function(function_params, z_n) z_n = eval_function(function_params, z_n)
if infinity is not None: if infinity is not None:
numpy.nan_to_num(z_n, copy=False, nan=infinity) np.nan_to_num(z_n, copy=False, nan=infinity)
z_n[abs(z_n) == numpy.inf] = infinity z_n[abs(z_n) == np.inf] = infinity
return z_n return z_n
@ -130,21 +128,21 @@ def show_results(
function_label: str, function_label: str,
function_params: Any, function_params: Any,
escape_radius: float, escape_radius: float,
z_final: numpy.ndarray, z_final: np.ndarray,
) -> None: ) -> None:
""" """
Plots of whether the absolute value of z_final is greater than Plots of whether the absolute value of z_final is greater than
the value of escape_radius. Adds the function_label and function_params to the value of escape_radius. Adds the function_label and function_params to
the title. the title.
>>> show_results('80', 0, 1, numpy.array([[0,1,.5],[.4,2,1.1],[.2,1,1.3]])) >>> show_results('80', 0, 1, np.array([[0,1,.5],[.4,2,1.1],[.2,1,1.3]]))
""" """
abs_z_final = (abs(z_final)).transpose() abs_z_final = (abs(z_final)).transpose()
abs_z_final[:, :] = abs_z_final[::-1, :] abs_z_final[:, :] = abs_z_final[::-1, :]
pyplot.matshow(abs_z_final < escape_radius) plt.matshow(abs_z_final < escape_radius)
pyplot.title(f"Julia set of ${function_label}$, $c={function_params}$") plt.title(f"Julia set of ${function_label}$, $c={function_params}$")
pyplot.show() plt.show()
def ignore_overflow_warnings() -> None: def ignore_overflow_warnings() -> None:

View File

@ -22,25 +22,25 @@ Requirements (pip):
from __future__ import annotations from __future__ import annotations
import matplotlib.pyplot as plt # type: ignore import matplotlib.pyplot as plt
import numpy import numpy as np
# initial triangle of Koch snowflake # initial triangle of Koch snowflake
VECTOR_1 = numpy.array([0, 0]) VECTOR_1 = np.array([0, 0])
VECTOR_2 = numpy.array([0.5, 0.8660254]) VECTOR_2 = np.array([0.5, 0.8660254])
VECTOR_3 = numpy.array([1, 0]) VECTOR_3 = np.array([1, 0])
INITIAL_VECTORS = [VECTOR_1, VECTOR_2, VECTOR_3, VECTOR_1] INITIAL_VECTORS = [VECTOR_1, VECTOR_2, VECTOR_3, VECTOR_1]
# uncomment for simple Koch curve instead of Koch snowflake # uncomment for simple Koch curve instead of Koch snowflake
# INITIAL_VECTORS = [VECTOR_1, VECTOR_3] # INITIAL_VECTORS = [VECTOR_1, VECTOR_3]
def iterate(initial_vectors: list[numpy.ndarray], steps: int) -> list[numpy.ndarray]: def iterate(initial_vectors: list[np.ndarray], steps: int) -> list[np.ndarray]:
""" """
Go through the number of iterations determined by the argument "steps". Go through the number of iterations determined by the argument "steps".
Be careful with high values (above 5) since the time to calculate increases Be careful with high values (above 5) since the time to calculate increases
exponentially. exponentially.
>>> iterate([numpy.array([0, 0]), numpy.array([1, 0])], 1) >>> iterate([np.array([0, 0]), np.array([1, 0])], 1)
[array([0, 0]), array([0.33333333, 0. ]), array([0.5 , \ [array([0, 0]), array([0.33333333, 0. ]), array([0.5 , \
0.28867513]), array([0.66666667, 0. ]), array([1, 0])] 0.28867513]), array([0.66666667, 0. ]), array([1, 0])]
""" """
@ -50,13 +50,13 @@ def iterate(initial_vectors: list[numpy.ndarray], steps: int) -> list[numpy.ndar
return vectors return vectors
def iteration_step(vectors: list[numpy.ndarray]) -> list[numpy.ndarray]: def iteration_step(vectors: list[np.ndarray]) -> list[np.ndarray]:
""" """
Loops through each pair of adjacent vectors. Each line between two adjacent Loops through each pair of adjacent vectors. Each line between two adjacent
vectors is divided into 4 segments by adding 3 additional vectors in-between vectors is divided into 4 segments by adding 3 additional vectors in-between
the original two vectors. The vector in the middle is constructed through a the original two vectors. The vector in the middle is constructed through a
60 degree rotation so it is bent outwards. 60 degree rotation so it is bent outwards.
>>> iteration_step([numpy.array([0, 0]), numpy.array([1, 0])]) >>> iteration_step([np.array([0, 0]), np.array([1, 0])])
[array([0, 0]), array([0.33333333, 0. ]), array([0.5 , \ [array([0, 0]), array([0.33333333, 0. ]), array([0.5 , \
0.28867513]), array([0.66666667, 0. ]), array([1, 0])] 0.28867513]), array([0.66666667, 0. ]), array([1, 0])]
""" """
@ -74,22 +74,22 @@ def iteration_step(vectors: list[numpy.ndarray]) -> list[numpy.ndarray]:
return new_vectors return new_vectors
def rotate(vector: numpy.ndarray, angle_in_degrees: float) -> numpy.ndarray: def rotate(vector: np.ndarray, angle_in_degrees: float) -> np.ndarray:
""" """
Standard rotation of a 2D vector with a rotation matrix Standard rotation of a 2D vector with a rotation matrix
(see https://en.wikipedia.org/wiki/Rotation_matrix ) (see https://en.wikipedia.org/wiki/Rotation_matrix )
>>> rotate(numpy.array([1, 0]), 60) >>> rotate(np.array([1, 0]), 60)
array([0.5 , 0.8660254]) array([0.5 , 0.8660254])
>>> rotate(numpy.array([1, 0]), 90) >>> rotate(np.array([1, 0]), 90)
array([6.123234e-17, 1.000000e+00]) array([6.123234e-17, 1.000000e+00])
""" """
theta = numpy.radians(angle_in_degrees) theta = np.radians(angle_in_degrees)
c, s = numpy.cos(theta), numpy.sin(theta) c, s = np.cos(theta), np.sin(theta)
rotation_matrix = numpy.array(((c, -s), (s, c))) rotation_matrix = np.array(((c, -s), (s, c)))
return numpy.dot(rotation_matrix, vector) return np.dot(rotation_matrix, vector)
def plot(vectors: list[numpy.ndarray]) -> None: def plot(vectors: list[np.ndarray]) -> None:
""" """
Utility function to plot the vectors using matplotlib.pyplot Utility function to plot the vectors using matplotlib.pyplot
No doctest was implemented since this function does not have a return value No doctest was implemented since this function does not have a return value

View File

@ -78,7 +78,7 @@ class BezierCurve:
step_size: defines the step(s) at which to evaluate the Bezier curve. step_size: defines the step(s) at which to evaluate the Bezier curve.
The smaller the step size, the finer the curve produced. The smaller the step size, the finer the curve produced.
""" """
from matplotlib import pyplot as plt # type: ignore from matplotlib import pyplot as plt
to_plot_x: list[float] = [] # x coordinates of points to plot to_plot_x: list[float] = [] # x coordinates of points to plot
to_plot_y: list[float] = [] # y coordinates of points to plot to_plot_y: list[float] = [] # y coordinates of points to plot

View File

@ -3,7 +3,7 @@ Implementation of gradient descent algorithm for minimizing cost of a linear hyp
function. function.
""" """
import numpy import numpy as np
# List of input, output pairs # List of input, output pairs
train_data = ( train_data = (
@ -116,7 +116,7 @@ def run_gradient_descent():
temp_parameter_vector[i] = ( temp_parameter_vector[i] = (
parameter_vector[i] - LEARNING_RATE * cost_derivative parameter_vector[i] - LEARNING_RATE * cost_derivative
) )
if numpy.allclose( if np.allclose(
parameter_vector, parameter_vector,
temp_parameter_vector, temp_parameter_vector,
atol=absolute_error_limit, atol=absolute_error_limit,

View File

@ -22,7 +22,7 @@ import os
import typing import typing
import urllib import urllib
import numpy import numpy as np
from tensorflow.python.framework import dtypes, random_seed from tensorflow.python.framework import dtypes, 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
@ -39,8 +39,8 @@ DEFAULT_SOURCE_URL = "https://storage.googleapis.com/cvdf-datasets/mnist/"
def _read32(bytestream): def _read32(bytestream):
dt = numpy.dtype(numpy.uint32).newbyteorder(">") dt = np.dtype(np.uint32).newbyteorder(">")
return numpy.frombuffer(bytestream.read(4), dtype=dt)[0] return np.frombuffer(bytestream.read(4), dtype=dt)[0]
@deprecated(None, "Please use tf.data to implement this functionality.") @deprecated(None, "Please use tf.data to implement this functionality.")
@ -68,7 +68,7 @@ def _extract_images(f):
rows = _read32(bytestream) rows = _read32(bytestream)
cols = _read32(bytestream) cols = _read32(bytestream)
buf = bytestream.read(rows * cols * num_images) buf = bytestream.read(rows * cols * num_images)
data = numpy.frombuffer(buf, dtype=numpy.uint8) data = np.frombuffer(buf, dtype=np.uint8)
data = data.reshape(num_images, rows, cols, 1) data = data.reshape(num_images, rows, cols, 1)
return data return data
@ -77,8 +77,8 @@ def _extract_images(f):
def _dense_to_one_hot(labels_dense, num_classes): def _dense_to_one_hot(labels_dense, num_classes):
"""Convert class labels from scalars to one-hot vectors.""" """Convert class labels from scalars to one-hot vectors."""
num_labels = labels_dense.shape[0] num_labels = labels_dense.shape[0]
index_offset = numpy.arange(num_labels) * num_classes index_offset = np.arange(num_labels) * num_classes
labels_one_hot = numpy.zeros((num_labels, num_classes)) labels_one_hot = np.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot return labels_one_hot
@ -107,7 +107,7 @@ def _extract_labels(f, one_hot=False, num_classes=10):
) )
num_items = _read32(bytestream) num_items = _read32(bytestream)
buf = bytestream.read(num_items) buf = bytestream.read(num_items)
labels = numpy.frombuffer(buf, dtype=numpy.uint8) labels = np.frombuffer(buf, dtype=np.uint8)
if one_hot: if one_hot:
return _dense_to_one_hot(labels, num_classes) return _dense_to_one_hot(labels, num_classes)
return labels return labels
@ -153,7 +153,7 @@ class _DataSet:
""" """
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) np.random.seed(seed1 if seed is None else seed2)
dtype = dtypes.as_dtype(dtype).base_dtype dtype = dtypes.as_dtype(dtype).base_dtype
if dtype not in (dtypes.uint8, dtypes.float32): if dtype not in (dtypes.uint8, dtypes.float32):
raise TypeError("Invalid image dtype %r, expected uint8 or float32" % dtype) raise TypeError("Invalid image dtype %r, expected uint8 or float32" % dtype)
@ -175,8 +175,8 @@ class _DataSet:
) )
if dtype == dtypes.float32: if dtype == dtypes.float32:
# Convert from [0, 255] -> [0.0, 1.0]. # Convert from [0, 255] -> [0.0, 1.0].
images = images.astype(numpy.float32) images = images.astype(np.float32)
images = numpy.multiply(images, 1.0 / 255.0) images = np.multiply(images, 1.0 / 255.0)
self._images = images self._images = images
self._labels = labels self._labels = labels
self._epochs_completed = 0 self._epochs_completed = 0
@ -210,8 +210,8 @@ class _DataSet:
start = self._index_in_epoch start = self._index_in_epoch
# Shuffle for the first epoch # Shuffle for the first epoch
if self._epochs_completed == 0 and start == 0 and shuffle: if self._epochs_completed == 0 and start == 0 and shuffle:
perm0 = numpy.arange(self._num_examples) perm0 = np.arange(self._num_examples)
numpy.random.shuffle(perm0) np.random.shuffle(perm0)
self._images = self.images[perm0] self._images = self.images[perm0]
self._labels = self.labels[perm0] self._labels = self.labels[perm0]
# Go to the next epoch # Go to the next epoch
@ -224,8 +224,8 @@ class _DataSet:
labels_rest_part = self._labels[start : self._num_examples] labels_rest_part = self._labels[start : self._num_examples]
# Shuffle the data # Shuffle the data
if shuffle: if shuffle:
perm = numpy.arange(self._num_examples) perm = np.arange(self._num_examples)
numpy.random.shuffle(perm) np.random.shuffle(perm)
self._images = self.images[perm] self._images = self.images[perm]
self._labels = self.labels[perm] self._labels = self.labels[perm]
# Start next epoch # Start next epoch
@ -235,8 +235,8 @@ class _DataSet:
images_new_part = self._images[start:end] images_new_part = self._images[start:end]
labels_new_part = self._labels[start:end] labels_new_part = self._labels[start:end]
return ( return (
numpy.concatenate((images_rest_part, images_new_part), axis=0), np.concatenate((images_rest_part, images_new_part), axis=0),
numpy.concatenate((labels_rest_part, labels_new_part), axis=0), np.concatenate((labels_rest_part, labels_new_part), axis=0),
) )
else: else:
self._index_in_epoch += batch_size self._index_in_epoch += batch_size

View File

@ -5,11 +5,11 @@ References:
- https://en.wikipedia.org/wiki/Feedforward_neural_network (Feedforward) - https://en.wikipedia.org/wiki/Feedforward_neural_network (Feedforward)
""" """
import numpy import numpy as np
class TwoHiddenLayerNeuralNetwork: class TwoHiddenLayerNeuralNetwork:
def __init__(self, input_array: numpy.ndarray, output_array: numpy.ndarray) -> None: def __init__(self, input_array: np.ndarray, output_array: np.ndarray) -> None:
""" """
This function initializes the TwoHiddenLayerNeuralNetwork class with random This function initializes the TwoHiddenLayerNeuralNetwork class with random
weights for every layer and initializes predicted output with zeroes. weights for every layer and initializes predicted output with zeroes.
@ -28,30 +28,28 @@ class TwoHiddenLayerNeuralNetwork:
# Random initial weights are assigned. # Random initial weights are assigned.
# self.input_array.shape[1] is used to represent number of nodes in input layer. # self.input_array.shape[1] is used to represent number of nodes in input layer.
# First hidden layer consists of 4 nodes. # First hidden layer consists of 4 nodes.
self.input_layer_and_first_hidden_layer_weights = numpy.random.rand( self.input_layer_and_first_hidden_layer_weights = np.random.rand(
self.input_array.shape[1], 4 self.input_array.shape[1], 4
) )
# Random initial values for the first hidden layer. # Random initial values for the first hidden layer.
# First hidden layer has 4 nodes. # First hidden layer has 4 nodes.
# Second hidden layer has 3 nodes. # Second hidden layer has 3 nodes.
self.first_hidden_layer_and_second_hidden_layer_weights = numpy.random.rand( self.first_hidden_layer_and_second_hidden_layer_weights = np.random.rand(4, 3)
4, 3
)
# Random initial values for the second hidden layer. # Random initial values for the second hidden layer.
# Second hidden layer has 3 nodes. # Second hidden layer has 3 nodes.
# Output layer has 1 node. # Output layer has 1 node.
self.second_hidden_layer_and_output_layer_weights = numpy.random.rand(3, 1) self.second_hidden_layer_and_output_layer_weights = np.random.rand(3, 1)
# Real output values provided. # Real output values provided.
self.output_array = output_array self.output_array = output_array
# Predicted output values by the neural network. # Predicted output values by the neural network.
# Predicted_output array initially consists of zeroes. # Predicted_output array initially consists of zeroes.
self.predicted_output = numpy.zeros(output_array.shape) self.predicted_output = np.zeros(output_array.shape)
def feedforward(self) -> numpy.ndarray: def feedforward(self) -> np.ndarray:
""" """
The information moves in only one direction i.e. forward from the input nodes, The information moves in only one direction i.e. forward from the input nodes,
through the two hidden nodes and to the output nodes. through the two hidden nodes and to the output nodes.
@ -60,24 +58,24 @@ class TwoHiddenLayerNeuralNetwork:
Return layer_between_second_hidden_layer_and_output Return layer_between_second_hidden_layer_and_output
(i.e the last layer of the neural network). (i.e the last layer of the neural network).
>>> input_val = numpy.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float) >>> input_val = np.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float)
>>> output_val = numpy.array(([0], [0], [0]), dtype=float) >>> output_val = np.array(([0], [0], [0]), dtype=float)
>>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val)
>>> res = nn.feedforward() >>> res = nn.feedforward()
>>> array_sum = numpy.sum(res) >>> array_sum = np.sum(res)
>>> numpy.isnan(array_sum) >>> np.isnan(array_sum)
False False
""" """
# Layer_between_input_and_first_hidden_layer is the layer connecting the # Layer_between_input_and_first_hidden_layer is the layer connecting the
# input nodes with the first hidden layer nodes. # input nodes with the first hidden layer nodes.
self.layer_between_input_and_first_hidden_layer = sigmoid( self.layer_between_input_and_first_hidden_layer = sigmoid(
numpy.dot(self.input_array, self.input_layer_and_first_hidden_layer_weights) np.dot(self.input_array, self.input_layer_and_first_hidden_layer_weights)
) )
# layer_between_first_hidden_layer_and_second_hidden_layer is the layer # layer_between_first_hidden_layer_and_second_hidden_layer is the layer
# connecting the first hidden set of nodes with the second hidden set of nodes. # connecting the first hidden set of nodes with the second hidden set of nodes.
self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid( self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid(
numpy.dot( np.dot(
self.layer_between_input_and_first_hidden_layer, self.layer_between_input_and_first_hidden_layer,
self.first_hidden_layer_and_second_hidden_layer_weights, self.first_hidden_layer_and_second_hidden_layer_weights,
) )
@ -86,7 +84,7 @@ class TwoHiddenLayerNeuralNetwork:
# layer_between_second_hidden_layer_and_output is the layer connecting # layer_between_second_hidden_layer_and_output is the layer connecting
# second hidden layer with the output node. # second hidden layer with the output node.
self.layer_between_second_hidden_layer_and_output = sigmoid( self.layer_between_second_hidden_layer_and_output = sigmoid(
numpy.dot( np.dot(
self.layer_between_first_hidden_layer_and_second_hidden_layer, self.layer_between_first_hidden_layer_and_second_hidden_layer,
self.second_hidden_layer_and_output_layer_weights, self.second_hidden_layer_and_output_layer_weights,
) )
@ -100,8 +98,8 @@ class TwoHiddenLayerNeuralNetwork:
error rate obtained in the previous epoch (i.e., iteration). error rate obtained in the previous epoch (i.e., iteration).
Updation is done using derivative of sogmoid activation function. Updation is done using derivative of sogmoid activation function.
>>> input_val = numpy.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float) >>> input_val = np.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float)
>>> output_val = numpy.array(([0], [0], [0]), dtype=float) >>> output_val = np.array(([0], [0], [0]), dtype=float)
>>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val)
>>> res = nn.feedforward() >>> res = nn.feedforward()
>>> nn.back_propagation() >>> nn.back_propagation()
@ -110,15 +108,15 @@ class TwoHiddenLayerNeuralNetwork:
False False
""" """
updated_second_hidden_layer_and_output_layer_weights = numpy.dot( updated_second_hidden_layer_and_output_layer_weights = np.dot(
self.layer_between_first_hidden_layer_and_second_hidden_layer.T, self.layer_between_first_hidden_layer_and_second_hidden_layer.T,
2 2
* (self.output_array - self.predicted_output) * (self.output_array - self.predicted_output)
* sigmoid_derivative(self.predicted_output), * sigmoid_derivative(self.predicted_output),
) )
updated_first_hidden_layer_and_second_hidden_layer_weights = numpy.dot( updated_first_hidden_layer_and_second_hidden_layer_weights = np.dot(
self.layer_between_input_and_first_hidden_layer.T, self.layer_between_input_and_first_hidden_layer.T,
numpy.dot( np.dot(
2 2
* (self.output_array - self.predicted_output) * (self.output_array - self.predicted_output)
* sigmoid_derivative(self.predicted_output), * sigmoid_derivative(self.predicted_output),
@ -128,10 +126,10 @@ class TwoHiddenLayerNeuralNetwork:
self.layer_between_first_hidden_layer_and_second_hidden_layer self.layer_between_first_hidden_layer_and_second_hidden_layer
), ),
) )
updated_input_layer_and_first_hidden_layer_weights = numpy.dot( updated_input_layer_and_first_hidden_layer_weights = np.dot(
self.input_array.T, self.input_array.T,
numpy.dot( np.dot(
numpy.dot( np.dot(
2 2
* (self.output_array - self.predicted_output) * (self.output_array - self.predicted_output)
* sigmoid_derivative(self.predicted_output), * sigmoid_derivative(self.predicted_output),
@ -155,7 +153,7 @@ class TwoHiddenLayerNeuralNetwork:
updated_second_hidden_layer_and_output_layer_weights updated_second_hidden_layer_and_output_layer_weights
) )
def train(self, output: numpy.ndarray, iterations: int, give_loss: bool) -> None: def train(self, output: np.ndarray, iterations: int, give_loss: bool) -> None:
""" """
Performs the feedforwarding and back propagation process for the Performs the feedforwarding and back propagation process for the
given number of iterations. given number of iterations.
@ -166,8 +164,8 @@ class TwoHiddenLayerNeuralNetwork:
give_loss : boolean value, If True then prints loss for each iteration, give_loss : boolean value, If True then prints loss for each iteration,
If False then nothing is printed If False then nothing is printed
>>> input_val = numpy.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float) >>> input_val = np.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float)
>>> output_val = numpy.array(([0], [1], [1]), dtype=float) >>> output_val = np.array(([0], [1], [1]), dtype=float)
>>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val)
>>> first_iteration_weights = nn.feedforward() >>> first_iteration_weights = nn.feedforward()
>>> nn.back_propagation() >>> nn.back_propagation()
@ -179,10 +177,10 @@ class TwoHiddenLayerNeuralNetwork:
self.output = self.feedforward() self.output = self.feedforward()
self.back_propagation() self.back_propagation()
if give_loss: if give_loss:
loss = numpy.mean(numpy.square(output - self.feedforward())) loss = np.mean(np.square(output - self.feedforward()))
print(f"Iteration {iteration} Loss: {loss}") print(f"Iteration {iteration} Loss: {loss}")
def predict(self, input_arr: numpy.ndarray) -> int: def predict(self, input_arr: np.ndarray) -> int:
""" """
Predict's the output for the given input values using Predict's the output for the given input values using
the trained neural network. the trained neural network.
@ -192,8 +190,8 @@ class TwoHiddenLayerNeuralNetwork:
than the threshold value else returns 0, than the threshold value else returns 0,
as the real output values are in binary. as the real output values are in binary.
>>> input_val = numpy.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float) >>> input_val = np.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float)
>>> output_val = numpy.array(([0], [1], [1]), dtype=float) >>> output_val = np.array(([0], [1], [1]), dtype=float)
>>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val)
>>> nn.train(output_val, 1000, False) >>> nn.train(output_val, 1000, False)
>>> nn.predict([0, 1, 0]) in (0, 1) >>> nn.predict([0, 1, 0]) in (0, 1)
@ -204,18 +202,18 @@ class TwoHiddenLayerNeuralNetwork:
self.array = input_arr self.array = input_arr
self.layer_between_input_and_first_hidden_layer = sigmoid( self.layer_between_input_and_first_hidden_layer = sigmoid(
numpy.dot(self.array, self.input_layer_and_first_hidden_layer_weights) np.dot(self.array, self.input_layer_and_first_hidden_layer_weights)
) )
self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid( self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid(
numpy.dot( np.dot(
self.layer_between_input_and_first_hidden_layer, self.layer_between_input_and_first_hidden_layer,
self.first_hidden_layer_and_second_hidden_layer_weights, self.first_hidden_layer_and_second_hidden_layer_weights,
) )
) )
self.layer_between_second_hidden_layer_and_output = sigmoid( self.layer_between_second_hidden_layer_and_output = sigmoid(
numpy.dot( np.dot(
self.layer_between_first_hidden_layer_and_second_hidden_layer, self.layer_between_first_hidden_layer_and_second_hidden_layer,
self.second_hidden_layer_and_output_layer_weights, self.second_hidden_layer_and_output_layer_weights,
) )
@ -224,26 +222,26 @@ class TwoHiddenLayerNeuralNetwork:
return int((self.layer_between_second_hidden_layer_and_output > 0.6)[0]) return int((self.layer_between_second_hidden_layer_and_output > 0.6)[0])
def sigmoid(value: numpy.ndarray) -> numpy.ndarray: def sigmoid(value: np.ndarray) -> np.ndarray:
""" """
Applies sigmoid activation function. Applies sigmoid activation function.
return normalized values return normalized values
>>> sigmoid(numpy.array(([1, 0, 2], [1, 0, 0]), dtype=numpy.float64)) >>> sigmoid(np.array(([1, 0, 2], [1, 0, 0]), dtype=np.float64))
array([[0.73105858, 0.5 , 0.88079708], array([[0.73105858, 0.5 , 0.88079708],
[0.73105858, 0.5 , 0.5 ]]) [0.73105858, 0.5 , 0.5 ]])
""" """
return 1 / (1 + numpy.exp(-value)) return 1 / (1 + np.exp(-value))
def sigmoid_derivative(value: numpy.ndarray) -> numpy.ndarray: def sigmoid_derivative(value: np.ndarray) -> np.ndarray:
""" """
Provides the derivative value of the sigmoid function. Provides the derivative value of the sigmoid function.
returns derivative of the sigmoid value returns derivative of the sigmoid value
>>> sigmoid_derivative(numpy.array(([1, 0, 2], [1, 0, 0]), dtype=numpy.float64)) >>> sigmoid_derivative(np.array(([1, 0, 2], [1, 0, 0]), dtype=np.float64))
array([[ 0., 0., -2.], array([[ 0., 0., -2.],
[ 0., 0., 0.]]) [ 0., 0., 0.]])
""" """
@ -264,7 +262,7 @@ def example() -> int:
True True
""" """
# Input values. # Input values.
test_input = numpy.array( test_input = np.array(
( (
[0, 0, 0], [0, 0, 0],
[0, 0, 1], [0, 0, 1],
@ -275,11 +273,11 @@ def example() -> int:
[1, 1, 0], [1, 1, 0],
[1, 1, 1], [1, 1, 1],
), ),
dtype=numpy.float64, dtype=np.float64,
) )
# True output values for the given input values. # True output values for the given input values.
output = numpy.array(([0], [1], [1], [0], [1], [0], [0], [1]), dtype=numpy.float64) output = np.array(([0], [1], [1], [0], [1], [0], [0], [1]), dtype=np.float64)
# Calling neural network class. # Calling neural network class.
neural_network = TwoHiddenLayerNeuralNetwork( neural_network = TwoHiddenLayerNeuralNetwork(
@ -290,7 +288,7 @@ def example() -> int:
# Set give_loss to True if you want to see loss in every iteration. # Set give_loss to True if you want to see loss in every iteration.
neural_network.train(output=output, iterations=10, give_loss=False) neural_network.train(output=output, iterations=10, give_loss=False)
return neural_network.predict(numpy.array(([1, 1, 1]), dtype=numpy.float64)) return neural_network.predict(np.array(([1, 1, 1]), dtype=np.float64))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -6,7 +6,6 @@ lint.ignore = [ # `ruff rule S101` for a description of that rule
"EM101", # Exception must not use a string literal, assign to variable first "EM101", # Exception must not use a string literal, assign to variable first
"EXE001", # Shebang is present but file is not executable" -- FIX ME "EXE001", # Shebang is present but file is not executable" -- FIX ME
"G004", # Logging statement uses f-string "G004", # Logging statement uses f-string
"ICN001", # `matplotlib.pyplot` should be imported as `plt` -- FIX ME
"INP001", # File `x/y/z.py` is part of an implicit namespace package. Add an `__init__.py`. -- FIX ME "INP001", # File `x/y/z.py` is part of an implicit namespace package. Add an `__init__.py`. -- FIX ME
"NPY002", # Replace legacy `np.random.choice` call with `np.random.Generator` -- FIX ME "NPY002", # Replace legacy `np.random.choice` call with `np.random.Generator` -- FIX ME
"PGH003", # Use specific rule codes when ignoring type issues -- FIX ME "PGH003", # Use specific rule codes when ignoring type issues -- FIX ME