afmaths 2.0.2__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afmaths
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: A simple package of math functions.
5
5
  Home-page: https://github.com/Arturius771/afmaths
6
6
  Author: Artur Foden
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afmaths
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: A simple package of math functions.
5
5
  Home-page: https://github.com/Arturius771/afmaths
6
6
  Author: Artur Foden
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ setup.py
3
+ afmaths.egg-info/PKG-INFO
4
+ afmaths.egg-info/SOURCES.txt
5
+ afmaths.egg-info/dependency_links.txt
6
+ afmaths.egg-info/top_level.txt
7
+ lib/__init__.py
8
+ lib/cs.py
9
+ lib/formula.py
10
+ lib/geometry.py
11
+ lib/graph.py
12
+ lib/list.py
13
+ lib/operation.py
14
+ lib/physics.py
15
+ lib/space_engineering.py
16
+ lib/statistics.py
@@ -0,0 +1 @@
1
+ lib
File without changes
@@ -0,0 +1,190 @@
1
+ import math
2
+ from geometry import pythagoras
3
+ from operation import (
4
+ HALF,
5
+ add,
6
+ divide,
7
+ exponentiate,
8
+ factorial,
9
+ multiply,
10
+ subtract,
11
+ )
12
+ from list import sum
13
+
14
+
15
+ def file_compression_ratio(uncompressed_size: float):
16
+ return lambda compressed_size: divide(compressed_size)(uncompressed_size)
17
+
18
+
19
+ def compressed_file_size(uncompressed_size):
20
+ return lambda compression_ratio: divide(compression_ratio)(uncompressed_size)
21
+
22
+
23
+ def diagonal_pixel_length(length_in_pixels):
24
+ return lambda width_in_pixels: math.floor(
25
+ pythagoras(length_in_pixels)(width_in_pixels)
26
+ )
27
+
28
+
29
+ def travelling_salesman_problem_total_routes(number_of_cities) -> float:
30
+ ##(n - 1)!/2
31
+ subtract1 = subtract(1)
32
+ total_routes = HALF(factorial(subtract1(number_of_cities)))
33
+
34
+ return total_routes
35
+
36
+
37
+ def check_drive_clusters(
38
+ sectors_per_cluster, sector_size_bytes, physical_file_size_bytes
39
+ ) -> tuple[int, float]:
40
+ ## TM255
41
+ if (
42
+ physical_file_size_bytes % (multiply(sectors_per_cluster)(sector_size_bytes))
43
+ == 0
44
+ ):
45
+ number_of_clusters = physical_file_size_bytes // multiply(sectors_per_cluster)(
46
+ sector_size_bytes
47
+ )
48
+ else:
49
+ number_of_clusters = (
50
+ physical_file_size_bytes // (sectors_per_cluster * sector_size_bytes)
51
+ ) + 1
52
+
53
+ multiply_number_of_clusters = multiply(number_of_clusters)
54
+ multiply_number_of_clusters_by_sectors_per_cluster = multiply(
55
+ multiply_number_of_clusters(sectors_per_cluster)
56
+ )
57
+ slack_space_bytes = subtract(physical_file_size_bytes)(
58
+ multiply_number_of_clusters_by_sectors_per_cluster(sector_size_bytes)
59
+ )
60
+
61
+ return (number_of_clusters, slack_space_bytes)
62
+
63
+
64
+ def ml_f1_score(precision: float, recall: float) -> float:
65
+ """F1 score: related to the harmonic mean of precision and recall. Calculated as F1 = 2/[(1/Precision) + (1/Recall)] = 2/[(TP + FP)/TP + (TP + FN)/TP] = 2/[(2TP + FP + FN)/TP] = 2TP/[2TP + FP + FN] . A high F1 score implies the system has low numbers of false positives and false negatives. - TM358"""
66
+ f1 = divide(add(divide(precision)(1))(divide(recall)(1)))(2)
67
+
68
+ return f1
69
+
70
+
71
+ def ml_precesion(true_positives):
72
+ return lambda false_positives: divide(add(true_positives)(false_positives))(
73
+ true_positives
74
+ )
75
+
76
+
77
+ def ml_recall(true_positives):
78
+ """Fraction of total positives out of both true and false positives - also known as the true positive rate."""
79
+ return lambda false_negatives: divide(add(true_positives)(false_negatives))(
80
+ true_positives
81
+ ) # TM358
82
+
83
+
84
+ def ml_false_positive_rate(false_positives):
85
+ return lambda true_negatives: divide(add(false_positives)(true_negatives))(
86
+ false_positives
87
+ )
88
+
89
+
90
+ def ml_weighted_inputs(inputs: list[float], weights: list[float]) -> list[float] | None:
91
+ "Multiply the inputs by the weights - TM358 Block 1"
92
+ weighted_inputs = []
93
+ loop_count = 0
94
+ if len(inputs) != len(weights):
95
+ return None
96
+ for x in inputs:
97
+ weighted_inputs.append(multiply(x)(weights[inputs.index(x, loop_count)]))
98
+ loop_count += 1
99
+
100
+ return weighted_inputs
101
+
102
+
103
+ def ml_perceptron(inputs: list[float], weights: list[float], bias: float = 0) -> float:
104
+ x = ml_weighted_inputs(inputs, weights)
105
+ if x == None:
106
+ return 0 # TODO: this is dangerous
107
+ return ml_activation_function(add(sum(x))(bias))
108
+
109
+
110
+ def ml_activation_function(input: float, threshold: float = 0):
111
+ if input > threshold:
112
+ return 1
113
+ else:
114
+ return 0
115
+
116
+
117
+ def byte_to_ascii_text(input: int) -> str:
118
+ # https://www.rapidtables.com/convert/number/binary-to-ascii.html
119
+ value = byte_to_decimal(input)
120
+
121
+ return chr(value)
122
+
123
+
124
+ def byte_to_decimal(input: int) -> int:
125
+ """Takes an 8 bit value and returns its value in decimal form."""
126
+ value = 0
127
+ tracker = len(str(input)) - 1
128
+
129
+ for bit in str(input):
130
+ if int(bit) != 0:
131
+ exponentiateByTracker = exponentiate(tracker)
132
+ value += exponentiateByTracker(2)
133
+ tracker -= 1
134
+ return value
135
+
136
+
137
+ def byte_to_hex(input: int) -> str:
138
+ str_input = str(input)
139
+ length = len(str_input)
140
+
141
+ if length == 8:
142
+ return f"{bit_to_hex(str_input[:4])}{bit_to_hex(str_input[4:])}"
143
+ if length == 7:
144
+ return f"{bit_to_hex(str_input[:3])}{bit_to_hex(str_input[3:])}"
145
+ if length == 6:
146
+ return f"{bit_to_hex(str_input[:2])}{bit_to_hex(str_input[2:])}"
147
+ if length == 5:
148
+ return f"{bit_to_hex(str_input[:1])}{bit_to_hex(str_input[1:])}"
149
+ if length <= 4:
150
+ return f"{bit_to_hex(str_input)}"
151
+
152
+ return str_input
153
+
154
+
155
+ def bit_to_hex(bit_string: str) -> str:
156
+ bit_string = bit_string
157
+ if bit_string == "0":
158
+ return "0"
159
+ if bit_string == "1":
160
+ return "1"
161
+ if bit_string == "10":
162
+ return "2"
163
+ if bit_string == "11":
164
+ return "3"
165
+ if bit_string == "100":
166
+ return "4"
167
+ if bit_string == "101":
168
+ return "5"
169
+ if bit_string == "110":
170
+ return "6"
171
+ if bit_string == "111":
172
+ return "7"
173
+ if bit_string == "1000":
174
+ return "8"
175
+ if bit_string == "1001":
176
+ return "9"
177
+ if bit_string == "1010":
178
+ return "A"
179
+ if bit_string == "1011":
180
+ return "B"
181
+ if bit_string == "1100":
182
+ return "C"
183
+ if bit_string == "1101":
184
+ return "D"
185
+ if bit_string == "1110":
186
+ return "E"
187
+ if bit_string == "1111":
188
+ return "F"
189
+
190
+ return bit_string
@@ -0,0 +1,66 @@
1
+ from functools import reduce
2
+ import math
3
+ from operation import (
4
+ SQUARE,
5
+ add,
6
+ divide,
7
+ exponentiate,
8
+ multiply,
9
+ factorial,
10
+ )
11
+
12
+
13
+ def sigmoid(input: float, bias: float = 0) -> float:
14
+ """Calculates the sigmoid of a value"""
15
+ # TM358 Section Block 1 section 5
16
+ add_bias = add(bias)
17
+ return divide(add(1)(exponentiate(add_bias(-input))(math.e)))(1)
18
+
19
+
20
+ def inverse_square_law(source_strength: float, distance_metres: float) -> float:
21
+ """Calculates the inverse square law"""
22
+ ##TM255 block 1
23
+ four_times_pi = multiply(4)(math.pi)
24
+ denominator = multiply(SQUARE(distance_metres))(four_times_pi)
25
+ return divide(denominator)(source_strength)
26
+
27
+
28
+ def taylor_series(value):
29
+ """Calculates the Taylor series of a value"""
30
+
31
+ # Written for sin and cos functions so may not be generic for pure Taylor Series functions.
32
+ def steps(
33
+ initial_value_in_series, increment=1, initial_denmoninator=1, steps=3, sign=-1
34
+ ):
35
+ taylor = [initial_value_in_series]
36
+ for _ in range(steps):
37
+ exponent = exponentiate(initial_denmoninator)
38
+ division = divide(factorial(initial_denmoninator))
39
+ taylor.append(division(exponent(value)))
40
+ initial_denmoninator += increment
41
+
42
+ for index in range(len(taylor)):
43
+ sign = -1 if sign == +1 else +1
44
+ taylor[index] = taylor[index] * sign
45
+
46
+ return reduce(lambda a, b: a + b, taylor)
47
+
48
+ return steps
49
+
50
+
51
+ def herons_method(value: float):
52
+ """
53
+ O(log precision) method for calculating square roots. The square roots of two values (eg. 25, 2982186) will be calculated in the same number of cycles to the same precision
54
+ """
55
+ # www.youtube.com/watch?v=l2TCgS_eLwA
56
+ initial_estimate = value / 2
57
+ current_step = initial_estimate
58
+ epsilon = value * exponentiate(-9)(10)
59
+
60
+ while True:
61
+ next_step = 1 / 2 * (current_step + (value / current_step))
62
+ if next_step < epsilon:
63
+ break
64
+ current_step = next_step
65
+
66
+ return current_step
@@ -0,0 +1,230 @@
1
+ from astronomy_types import (
2
+ Coordinate2D,
3
+ Distance,
4
+ Eccentricity,
5
+ Radians,
6
+ Ratio,
7
+ Scalar,
8
+ SemiMajorAxis,
9
+ TrueAnomaly,
10
+ )
11
+
12
+ from operation import HALF, SQUARE, add, divide, half, multiply, square, subtract
13
+ import math
14
+ from formula import taylor_series
15
+
16
+ pythagoras = lambda a: lambda b: add(SQUARE(a))(SQUARE(b))
17
+
18
+
19
+ def euclid(m: int, n: int) -> int:
20
+ """Given two positive integers, m and n, find their greatest common divisor which is the largest positive integer that divides both evenly."""
21
+
22
+ remainder = m % n
23
+ if remainder == 0:
24
+ return n
25
+ else:
26
+ m = n
27
+ n = remainder
28
+ euclid(m, n)
29
+ return n
30
+
31
+
32
+ def sieve_of_eratosthenes(n: int) -> list[int]:
33
+ """Finds prime numbers up to n"""
34
+ # https://www.youtube.com/watch?v=fwxjMKBMR7s
35
+ numbers = [True] * n
36
+ primes = []
37
+
38
+ for index in range(2, n):
39
+ if numbers[index]:
40
+ primes.append(index)
41
+ for multiple in range(index * index, n, index):
42
+ numbers[multiple] = False
43
+
44
+ return primes
45
+
46
+
47
+ def tangent(angle_degrees: float) -> float:
48
+ """Returns a value in radians"""
49
+ return divide(cosine(angle_degrees))(sine(angle_degrees))
50
+
51
+
52
+ def arctangent(radians):
53
+ return math.degrees(math.atan(radians))
54
+
55
+
56
+ def sine(angle_degrees: float) -> float:
57
+ """Returns a value in radians"""
58
+ return taylor_series(math.radians(angle_degrees))(math.radians(angle_degrees), 2, 3)
59
+
60
+
61
+ def cosine(angle_degrees: float) -> float:
62
+ """Returns a value in radians"""
63
+ return taylor_series(math.radians(angle_degrees))(1, 2, 2)
64
+
65
+
66
+ # TODO: Check naming, this may be valid for more than just right triangles
67
+ def area_of_right_triangle(base_length: float, height_length: float) -> float:
68
+ """Area = base * height / 2"""
69
+ return HALF(multiply(base_length)(height_length))
70
+
71
+
72
+ def area_of_quarter_circle(side_length: float, radius: float) -> float:
73
+ """Area = s^2 - ((1/4)*pi*r^2)"""
74
+ return subtract((1 / 4) * math.pi * SQUARE(radius))(SQUARE(side_length))
75
+
76
+
77
+ def semi_major_axis_from_axes(a: float, b: float) -> SemiMajorAxis:
78
+ """Returns the semi major axis of an ellipse given the lengths of the two axes"""
79
+ return HALF(add(a)(b))
80
+
81
+
82
+ def circle_bounding_box_from_coordinates(coordinates: Coordinate2D, radius: float):
83
+ """
84
+ Calculate the bounding box of a circle given its center coordinates and radius.
85
+
86
+ Parameters:
87
+ x (float): The x-coordinate of the circle's center.
88
+ y (float): The y-coordinate of the circle's center.
89
+ radius (float): The radius of the circle.
90
+
91
+ Returns:
92
+ tuple: A tuple containing the coordinates of the bounding box in the format (x0, y0, x1, y1).
93
+ """
94
+ return draw_circle_with_eccentricity(
95
+ coordinates, radius, Eccentricity(Ratio(Scalar(0)))
96
+ )
97
+
98
+
99
+ def draw_circle_with_eccentricity(
100
+ coordinates: Coordinate2D, radius: float, eccentricity: Eccentricity
101
+ ) -> tuple[Coordinate2D, Coordinate2D]:
102
+ """
103
+ Calculate the bounding box of an ellipse given its center coordinates, radius, and eccentricity.
104
+
105
+ Parameters:
106
+ x (float): The x-coordinate of the ellipse's center.
107
+ y (float): The y-coordinate of the ellipse's center.
108
+ radius (float): The semi-major axis of the ellipse.
109
+ eccentricity (float): The eccentricity of the ellipse (0 <= eccentricity < 1).
110
+
111
+ Returns:
112
+ tuple: A tuple containing the coordinates of the bounding box in the format (x0, y0, x1, y1).
113
+ """
114
+ if eccentricity < 0 or eccentricity >= 1:
115
+ raise ValueError("Eccentricity must be in the range [0, 1).")
116
+
117
+ semi_minor_axis = radius * (1 - eccentricity**2) ** 0.5
118
+ x0 = coordinates.x - radius
119
+ y0 = coordinates.y - semi_minor_axis
120
+ x1 = coordinates.x + radius
121
+ y1 = coordinates.y + semi_minor_axis
122
+ return (Coordinate2D(x0, y0), Coordinate2D(x1, y1))
123
+
124
+
125
+ def calculate_distance(
126
+ coordinates1: Coordinate2D, coordinates2: Coordinate2D
127
+ ) -> Distance:
128
+ """
129
+ Calculate the distance between two points in 2D space.
130
+
131
+ Parameters:
132
+ x1 (float): The x-coordinate of the first point.
133
+ y1 (float): The y-coordinate of the first point.
134
+ x2 (float): The x-coordinate of the second point.
135
+ y2 (float): The y-coordinate of the second point.
136
+
137
+ Returns:
138
+ float: The distance between the two points.
139
+ """
140
+ return (
141
+ (coordinates2.x - coordinates1.x) ** 2 + (coordinates2.y - coordinates1.y) ** 2
142
+ ) ** 0.5
143
+
144
+
145
+ def calculate_foci(
146
+ semi_major_axis: SemiMajorAxis, eccentricity: Eccentricity
147
+ ) -> tuple[Coordinate2D, Coordinate2D]:
148
+ """
149
+ Calculate the coordinates of the foci of an ellipse given its semi-major axis and eccentricity.
150
+
151
+ Parameters:
152
+ a (float): The semi-major axis of the ellipse.
153
+ e (float): The eccentricity of the ellipse (0 <= eccentricity < 1).
154
+
155
+ Returns:
156
+ tuple: A tuple containing the coordinates of the two foci in the format ((x1, y1), (x2, y2)).
157
+ """
158
+ if eccentricity < 0 or eccentricity >= 1:
159
+ raise ValueError("Eccentricity must be in the range [0, 1).")
160
+
161
+ c = semi_major_axis * eccentricity
162
+ # [X1, Y1] = (-c, 0) and [X2, Y2] = (c, 0) for an ellipse centered at the origin
163
+ return (Coordinate2D(-c, 0), Coordinate2D(c, 0))
164
+
165
+
166
+ def calculate_semi_major_axis(
167
+ radius: Distance, eccentricity: Eccentricity
168
+ ) -> SemiMajorAxis:
169
+ """
170
+ Calculate the semi-major axis of an ellipse given the distance from the center to a point on the ellipse and the eccentricity.
171
+
172
+ Parameters:
173
+ r (float): The distance from the center of the ellipse to a point on the ellipse.
174
+ e (float): The eccentricity of the ellipse (0 <= eccentricity < 1).
175
+
176
+ Returns:
177
+ float: The semi-major axis of the ellipse.
178
+ """
179
+ if eccentricity < 0 or eccentricity >= 1:
180
+ raise ValueError("Eccentricity must be in the range [0, 1).")
181
+
182
+ return SemiMajorAxis(Distance(Scalar(radius / (1 - eccentricity))))
183
+
184
+
185
+ def calculate_semi_minor_axis(
186
+ semi_major_axis: SemiMajorAxis, eccentricity: Eccentricity
187
+ ) -> float:
188
+ """
189
+ Calculate the semi-minor axis of an ellipse given its semi-major axis and eccentricity.
190
+
191
+ Parameters:
192
+ a (float): The semi-major axis of the ellipse.
193
+ e (float): The eccentricity of the ellipse (0 <= eccentricity < 1).
194
+
195
+ Returns:
196
+ float: The semi-minor axis of the ellipse.
197
+ """
198
+ if eccentricity < 0 or eccentricity >= 1:
199
+ raise ValueError("Eccentricity must be in the range [0, 1).")
200
+
201
+ return semi_major_axis * (1 - eccentricity**2) ** 0.5
202
+
203
+
204
+ def true_anomaly_from_eccentric_anomaly(
205
+ eccentric_anomaly, eccentricity: Eccentricity
206
+ ) -> TrueAnomaly:
207
+ """
208
+ Calculate the true anomaly from the eccentric anomaly and eccentricity.
209
+
210
+ Parameters:
211
+ E (float): The eccentric anomaly in radians.
212
+ e (float): The eccentricity of the orbit (0 <= eccentricity < 1).
213
+
214
+ Returns:
215
+ float: The true anomaly in radians.
216
+ """
217
+ if eccentricity < 0 or eccentricity >= 1:
218
+ raise ValueError("Eccentricity must be in the range [0, 1).")
219
+
220
+ return TrueAnomaly(
221
+ Radians(
222
+ Scalar(
223
+ 2
224
+ * math.atan2(
225
+ math.sqrt(1 + eccentricity) * math.sin(eccentric_anomaly / 2),
226
+ math.sqrt(1 - eccentricity) * math.cos(eccentric_anomaly / 2),
227
+ )
228
+ )
229
+ )
230
+ )
@@ -0,0 +1,38 @@
1
+ from dataclasses import dataclass
2
+
3
+ from operation import divide, multiply, subtract, termial
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class GraphCoordinates:
8
+ x: float
9
+ y: float
10
+
11
+
12
+ def slope_gradiant(point1: GraphCoordinates, point2: GraphCoordinates) -> float:
13
+ """Calculates the slope between two points"""
14
+ ##https://www.bbc.co.uk/bitesize/topics/zvhs34j/articles/z4ctng8
15
+ return divide(subtract(point1.x)(point2.x))(subtract(point1.y)(point2.y))
16
+
17
+
18
+ def equation_of_line(
19
+ point1: GraphCoordinates, point2: GraphCoordinates
20
+ ) -> tuple[float, float]:
21
+ """Returns the slope and y-intercept of the line passing through two points"""
22
+ ##m = gradient
23
+ m = slope_gradiant(point1, point2)
24
+ ##b = y intercept when x = 0
25
+ rhs = multiply(m)(point1.x)
26
+ b = subtract(rhs)(point1.y)
27
+ ##y = mx + b
28
+ return (m, b)
29
+
30
+
31
+ def interpolations_for_bezier_curve(number_of_control_points: int) -> int:
32
+ """Calculates the number of interpolations needed for a bezier curve with a given number of control points
33
+ interpolations = n(n+1)/2
34
+ """
35
+ # if points < 2:
36
+ # return 0
37
+ # return points - 1 + interpolations_for_bezier_curve(points - 1)
38
+ return termial(number_of_control_points)
@@ -0,0 +1,63 @@
1
+ import math
2
+ import statistics
3
+ from operation import divide, subtract
4
+
5
+
6
+ def sort(number_list: list[float]) -> list[float]:
7
+ return sorted(number_list)
8
+
9
+
10
+ def length(number_list: list[float]) -> int:
11
+ return len(number_list)
12
+
13
+
14
+ def sum(number_list: list[float]) -> float:
15
+ return math.sum(number_list)
16
+
17
+
18
+ def minimum(number_list: list[float]) -> float:
19
+ return min(number_list)
20
+
21
+
22
+ def maximum(number_list: list[float]) -> float:
23
+ return max(number_list)
24
+
25
+
26
+ def range(number_list: list[float]) -> float:
27
+ return subtract(minimum(number_list))(maximum(number_list))
28
+
29
+
30
+ def mean(number_list: list[float]) -> float:
31
+ return divide(length(number_list))(sum(number_list))
32
+
33
+
34
+ def median(number_list: list[float]) -> float:
35
+ return statistics.median(number_list)
36
+
37
+
38
+ def quartiles(number_list: list[float]) -> tuple[float, float, float]:
39
+ """Calculates the quartiles of a list of numbers"""
40
+ number_list = sorted(number_list)
41
+ q1_index = int(math.ceil(length(number_list) * 0.25))
42
+ q1_result = number_list[q1_index - 1]
43
+ number_list[0 : length(number_list) // 2]
44
+ q3_result = median(number_list)
45
+ iqr_result = subtract(q1_result)(q3_result)
46
+
47
+ return q1_result, q3_result, iqr_result
48
+
49
+
50
+ def dataplotter(number_list: list[float]) -> None:
51
+ ##MU123
52
+ """
53
+ Runs some useful functions on a provided list
54
+ """
55
+ sort(number_list)
56
+ length(number_list)
57
+ sum(number_list)
58
+ minimum(number_list)
59
+ maximum(number_list)
60
+ range(number_list)
61
+ mean(number_list)
62
+ median(number_list)
63
+ quartiles(number_list)