heropy 0.1.0__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.
- heropy-0.1.0/PKG-INFO +70 -0
- heropy-0.1.0/README.md +52 -0
- heropy-0.1.0/heropy/__init__.py +1 -0
- heropy-0.1.0/heropy/core.py +213 -0
- heropy-0.1.0/heropy/fft.py +41 -0
- heropy-0.1.0/heropy/linalg.py +53 -0
- heropy-0.1.0/heropy/random.py +39 -0
- heropy-0.1.0/heropy/tests/__init__.py +0 -0
- heropy-0.1.0/heropy/tests/test_all.py +58 -0
- heropy-0.1.0/heropy.egg-info/PKG-INFO +70 -0
- heropy-0.1.0/heropy.egg-info/SOURCES.txt +13 -0
- heropy-0.1.0/heropy.egg-info/dependency_links.txt +1 -0
- heropy-0.1.0/heropy.egg-info/top_level.txt +1 -0
- heropy-0.1.0/pyproject.toml +31 -0
- heropy-0.1.0/setup.cfg +4 -0
heropy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heropy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A high-performance fundamental package for scientific computing with multi-dimensional arrays, linear algebra, and FFT.
|
|
5
|
+
Author-email: Death Legion Team <contact@deathlegion.team>
|
|
6
|
+
Project-URL: Homepage, https://github.com/deathlegion/heropy
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/deathlegion/heropy/issues
|
|
8
|
+
Keywords: scientific computing,multi-dimensional arrays,linear algebra,FFT,matrix,numerical computing,data science,machine learning
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# HeroPy: High-Performance Scientific Computing in Python
|
|
20
|
+
|
|
21
|
+
HeroPy is the fundamental package for scientific computing with Python, meticulously crafted by the **Death Legion Team**. It provides a powerful N-dimensional array object, sophisticated mathematical functions, and the core data structures necessary for modern data science and machine learning.
|
|
22
|
+
|
|
23
|
+
[](https://badge.fury.io/py/heropy)
|
|
24
|
+
[](https://opensource.org/licenses/MIT)
|
|
25
|
+
|
|
26
|
+
## Why HeroPy?
|
|
27
|
+
|
|
28
|
+
In the evolving landscape of numerical computing, HeroPy stands as a robust foundation for handling large, multi-dimensional arrays and matrices. Designed for performance and ease of use, HeroPy enables complex mathematical operations on entire blocks of data without the need for slow Python loops.
|
|
29
|
+
|
|
30
|
+
## Core Features
|
|
31
|
+
|
|
32
|
+
- **N-Dimensional Array (`ndarray`)**: A versatile, multi-dimensional array object with support for advanced indexing, slicing, and NumPy-style broadcasting.
|
|
33
|
+
- **Linear Algebra (`linalg`)**: High-level mathematical functions for matrix multiplication (`dot`), transposition, and vector operations.
|
|
34
|
+
- **Fourier Transforms (`fft`)**: Efficient Fast Fourier Transform (FFT) capabilities for signal processing and spectral analysis.
|
|
35
|
+
- **Random Number Generation (`random`)**: Sophisticated random number generation with support for various distributions like Uniform and Normal (Gaussian).
|
|
36
|
+
- **Extensible Architecture**: Built to be the bedrock of the Python data science ecosystem, compatible with machine learning and data analysis workflows.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Clone the repository
|
|
42
|
+
git clone <repo-url>
|
|
43
|
+
cd heropy
|
|
44
|
+
export PYTHONPATH=$PYTHONPATH:.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import heropy as hp
|
|
51
|
+
from heropy.linalg import dot
|
|
52
|
+
|
|
53
|
+
# Create arrays
|
|
54
|
+
a = hp.ndarray([[1, 2], [3, 4]])
|
|
55
|
+
b = hp.ndarray([10, 20])
|
|
56
|
+
|
|
57
|
+
# Arithmetic with broadcasting
|
|
58
|
+
c = a + b
|
|
59
|
+
|
|
60
|
+
# Matrix multiplication
|
|
61
|
+
d = dot(a, a)
|
|
62
|
+
|
|
63
|
+
# FFT
|
|
64
|
+
from heropy.fft import fft
|
|
65
|
+
freq = fft([1, 0, 1, 0])
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Performance Note
|
|
69
|
+
|
|
70
|
+
HeroPy is currently implemented in pure Python for maximum portability and clarity. While it provides the core data structures and operations, performance for very large datasets may be limited compared to C-accelerated libraries.
|
heropy-0.1.0/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# HeroPy: High-Performance Scientific Computing in Python
|
|
2
|
+
|
|
3
|
+
HeroPy is the fundamental package for scientific computing with Python, meticulously crafted by the **Death Legion Team**. It provides a powerful N-dimensional array object, sophisticated mathematical functions, and the core data structures necessary for modern data science and machine learning.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/py/heropy)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Why HeroPy?
|
|
9
|
+
|
|
10
|
+
In the evolving landscape of numerical computing, HeroPy stands as a robust foundation for handling large, multi-dimensional arrays and matrices. Designed for performance and ease of use, HeroPy enables complex mathematical operations on entire blocks of data without the need for slow Python loops.
|
|
11
|
+
|
|
12
|
+
## Core Features
|
|
13
|
+
|
|
14
|
+
- **N-Dimensional Array (`ndarray`)**: A versatile, multi-dimensional array object with support for advanced indexing, slicing, and NumPy-style broadcasting.
|
|
15
|
+
- **Linear Algebra (`linalg`)**: High-level mathematical functions for matrix multiplication (`dot`), transposition, and vector operations.
|
|
16
|
+
- **Fourier Transforms (`fft`)**: Efficient Fast Fourier Transform (FFT) capabilities for signal processing and spectral analysis.
|
|
17
|
+
- **Random Number Generation (`random`)**: Sophisticated random number generation with support for various distributions like Uniform and Normal (Gaussian).
|
|
18
|
+
- **Extensible Architecture**: Built to be the bedrock of the Python data science ecosystem, compatible with machine learning and data analysis workflows.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Clone the repository
|
|
24
|
+
git clone <repo-url>
|
|
25
|
+
cd heropy
|
|
26
|
+
export PYTHONPATH=$PYTHONPATH:.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import heropy as hp
|
|
33
|
+
from heropy.linalg import dot
|
|
34
|
+
|
|
35
|
+
# Create arrays
|
|
36
|
+
a = hp.ndarray([[1, 2], [3, 4]])
|
|
37
|
+
b = hp.ndarray([10, 20])
|
|
38
|
+
|
|
39
|
+
# Arithmetic with broadcasting
|
|
40
|
+
c = a + b
|
|
41
|
+
|
|
42
|
+
# Matrix multiplication
|
|
43
|
+
d = dot(a, a)
|
|
44
|
+
|
|
45
|
+
# FFT
|
|
46
|
+
from heropy.fft import fft
|
|
47
|
+
freq = fft([1, 0, 1, 0])
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Performance Note
|
|
51
|
+
|
|
52
|
+
HeroPy is currently implemented in pure Python for maximum portability and clarity. While it provides the core data structures and operations, performance for very large datasets may be limited compared to C-accelerated libraries.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import ndarray
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import itertools
|
|
3
|
+
|
|
4
|
+
class ndarray:
|
|
5
|
+
def __init__(self, data):
|
|
6
|
+
if isinstance(data, ndarray):
|
|
7
|
+
self._data = [x for x in data._data]
|
|
8
|
+
self._shape = data._shape
|
|
9
|
+
else:
|
|
10
|
+
self._data, self._shape = self._process_data(data)
|
|
11
|
+
|
|
12
|
+
self.size = 1
|
|
13
|
+
for dim in self._shape:
|
|
14
|
+
self.size *= dim
|
|
15
|
+
|
|
16
|
+
def _process_data(self, data):
|
|
17
|
+
if not isinstance(data, (list, tuple)):
|
|
18
|
+
return [data], ()
|
|
19
|
+
|
|
20
|
+
shape = []
|
|
21
|
+
curr = data
|
|
22
|
+
while isinstance(curr, (list, tuple)):
|
|
23
|
+
shape.append(len(curr))
|
|
24
|
+
if len(curr) == 0:
|
|
25
|
+
break
|
|
26
|
+
curr = curr[0]
|
|
27
|
+
|
|
28
|
+
def flatten(lst):
|
|
29
|
+
res = []
|
|
30
|
+
for item in lst:
|
|
31
|
+
if isinstance(item, (list, tuple)):
|
|
32
|
+
res.extend(flatten(item))
|
|
33
|
+
else:
|
|
34
|
+
res.append(item)
|
|
35
|
+
return res
|
|
36
|
+
|
|
37
|
+
return flatten(data), tuple(shape)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def shape(self):
|
|
41
|
+
return self._shape
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"ndarray({self._data}, shape={self._shape})"
|
|
45
|
+
|
|
46
|
+
def __len__(self):
|
|
47
|
+
if not self._shape:
|
|
48
|
+
return 0
|
|
49
|
+
return self._shape[0]
|
|
50
|
+
|
|
51
|
+
def _get_index(self, key):
|
|
52
|
+
if not isinstance(key, tuple):
|
|
53
|
+
key = (key,)
|
|
54
|
+
|
|
55
|
+
if len(key) > len(self._shape):
|
|
56
|
+
raise IndexError("Too many indices for array")
|
|
57
|
+
|
|
58
|
+
# Pad with full slices if necessary
|
|
59
|
+
key = list(key)
|
|
60
|
+
while len(key) < len(self._shape):
|
|
61
|
+
key.append(slice(None))
|
|
62
|
+
|
|
63
|
+
return key
|
|
64
|
+
|
|
65
|
+
def _resolve_key(self, key):
|
|
66
|
+
key = self._get_index(key)
|
|
67
|
+
slices = []
|
|
68
|
+
is_single = True
|
|
69
|
+
for i, k in enumerate(key):
|
|
70
|
+
if isinstance(k, int):
|
|
71
|
+
slices.append(slice(k, k + 1))
|
|
72
|
+
else:
|
|
73
|
+
slices.append(k)
|
|
74
|
+
is_single = False
|
|
75
|
+
|
|
76
|
+
new_shape = []
|
|
77
|
+
ranges = []
|
|
78
|
+
for i, s in enumerate(slices):
|
|
79
|
+
start, stop, step = s.indices(self._shape[i])
|
|
80
|
+
ranges.append(range(start, stop, step))
|
|
81
|
+
if not isinstance(key[i], int):
|
|
82
|
+
new_shape.append(len(ranges[-1]))
|
|
83
|
+
|
|
84
|
+
return ranges, tuple(new_shape), is_single
|
|
85
|
+
|
|
86
|
+
def __getitem__(self, key):
|
|
87
|
+
ranges, new_shape, is_single = self._resolve_key(key)
|
|
88
|
+
|
|
89
|
+
new_data = []
|
|
90
|
+
for coords in itertools.product(*ranges):
|
|
91
|
+
idx = 0
|
|
92
|
+
stride = 1
|
|
93
|
+
for i in range(len(self._shape) - 1, -1, -1):
|
|
94
|
+
idx += coords[i] * stride
|
|
95
|
+
stride *= self._shape[i]
|
|
96
|
+
new_data.append(self._data[idx])
|
|
97
|
+
|
|
98
|
+
if is_single:
|
|
99
|
+
return new_data[0]
|
|
100
|
+
|
|
101
|
+
res = ndarray(0)
|
|
102
|
+
res._data = new_data
|
|
103
|
+
res._shape = new_shape
|
|
104
|
+
res.size = len(new_data)
|
|
105
|
+
return res
|
|
106
|
+
|
|
107
|
+
def __setitem__(self, key, value):
|
|
108
|
+
ranges, _, is_single = self._resolve_key(key)
|
|
109
|
+
|
|
110
|
+
if is_single:
|
|
111
|
+
idx = 0
|
|
112
|
+
stride = 1
|
|
113
|
+
coords = [r.start for r in ranges]
|
|
114
|
+
for i in range(len(self._shape) - 1, -1, -1):
|
|
115
|
+
idx += coords[i] * stride
|
|
116
|
+
stride *= self._shape[i]
|
|
117
|
+
self._data[idx] = value
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
if isinstance(value, ndarray):
|
|
121
|
+
val_data = value._data
|
|
122
|
+
elif isinstance(value, (list, tuple)):
|
|
123
|
+
val_data = ndarray(value)._data
|
|
124
|
+
else:
|
|
125
|
+
val_data = itertools.cycle([value])
|
|
126
|
+
|
|
127
|
+
for i, coords in enumerate(itertools.product(*ranges)):
|
|
128
|
+
idx = 0
|
|
129
|
+
stride = 1
|
|
130
|
+
for j in range(len(self._shape) - 1, -1, -1):
|
|
131
|
+
idx += coords[j] * stride
|
|
132
|
+
stride *= self._shape[j]
|
|
133
|
+
|
|
134
|
+
if isinstance(val_data, itertools.cycle):
|
|
135
|
+
self._data[idx] = next(val_data)
|
|
136
|
+
else:
|
|
137
|
+
self._data[idx] = val_data[i]
|
|
138
|
+
|
|
139
|
+
def __add__(self, other):
|
|
140
|
+
return self._binary_op(other, lambda x, y: x + y)
|
|
141
|
+
|
|
142
|
+
def __sub__(self, other):
|
|
143
|
+
return self._binary_op(other, lambda x, y: x - y)
|
|
144
|
+
|
|
145
|
+
def __mul__(self, other):
|
|
146
|
+
return self._binary_op(other, lambda x, y: x * y)
|
|
147
|
+
|
|
148
|
+
def __truediv__(self, other):
|
|
149
|
+
return self._binary_op(other, lambda x, y: x / y)
|
|
150
|
+
|
|
151
|
+
def __radd__(self, other):
|
|
152
|
+
return ndarray(other) + self
|
|
153
|
+
|
|
154
|
+
def __rsub__(self, other):
|
|
155
|
+
return ndarray(other) - self
|
|
156
|
+
|
|
157
|
+
def __rmul__(self, other):
|
|
158
|
+
return ndarray(other) * self
|
|
159
|
+
|
|
160
|
+
def __rtruediv__(self, other):
|
|
161
|
+
return ndarray(other) / self
|
|
162
|
+
|
|
163
|
+
def _binary_op(self, other, op):
|
|
164
|
+
if not isinstance(other, ndarray):
|
|
165
|
+
other = ndarray(other)
|
|
166
|
+
|
|
167
|
+
# Get common shape for broadcasting
|
|
168
|
+
s1 = self.shape
|
|
169
|
+
s2 = other.shape
|
|
170
|
+
|
|
171
|
+
# Pad shapes with 1s to match lengths
|
|
172
|
+
l1, l2 = len(s1), len(s2)
|
|
173
|
+
n = max(l1, l2)
|
|
174
|
+
p1 = (1,) * (n - l1) + s1
|
|
175
|
+
p2 = (1,) * (n - l2) + s2
|
|
176
|
+
|
|
177
|
+
out_shape = []
|
|
178
|
+
for d1, d2 in zip(p1, p2):
|
|
179
|
+
if d1 == d2:
|
|
180
|
+
out_shape.append(d1)
|
|
181
|
+
elif d1 == 1:
|
|
182
|
+
out_shape.append(d2)
|
|
183
|
+
elif d2 == 1:
|
|
184
|
+
out_shape.append(d1)
|
|
185
|
+
else:
|
|
186
|
+
raise ValueError(f"Operands could not be broadcast together with shapes {s1} {s2}")
|
|
187
|
+
|
|
188
|
+
out_shape = tuple(out_shape)
|
|
189
|
+
|
|
190
|
+
# Simple but slow broadcasting implementation
|
|
191
|
+
ranges = [range(d) for d in out_shape]
|
|
192
|
+
new_data = []
|
|
193
|
+
for coords in itertools.product(*ranges):
|
|
194
|
+
# Map coords back to original shapes
|
|
195
|
+
c1 = []
|
|
196
|
+
for i in range(l1):
|
|
197
|
+
dim_idx = i + (n - l1)
|
|
198
|
+
c1.append(coords[dim_idx] if s1[i] > 1 else 0)
|
|
199
|
+
|
|
200
|
+
c2 = []
|
|
201
|
+
for i in range(l2):
|
|
202
|
+
dim_idx = i + (n - l2)
|
|
203
|
+
c2.append(coords[dim_idx] if s2[i] > 1 else 0)
|
|
204
|
+
|
|
205
|
+
v1 = self[tuple(c1)] if s1 else self._data[0]
|
|
206
|
+
v2 = other[tuple(c2)] if s2 else other._data[0]
|
|
207
|
+
new_data.append(op(v1, v2))
|
|
208
|
+
|
|
209
|
+
res = ndarray(0)
|
|
210
|
+
res._data = new_data
|
|
211
|
+
res._shape = out_shape
|
|
212
|
+
res.size = len(new_data)
|
|
213
|
+
return res
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import cmath
|
|
3
|
+
from .core import ndarray
|
|
4
|
+
|
|
5
|
+
def fft(x):
|
|
6
|
+
if not isinstance(x, ndarray):
|
|
7
|
+
x = ndarray(x)
|
|
8
|
+
|
|
9
|
+
if len(x.shape) != 1:
|
|
10
|
+
raise ValueError("FFT only implemented for 1D arrays")
|
|
11
|
+
|
|
12
|
+
n = x.size
|
|
13
|
+
if n <= 1:
|
|
14
|
+
return x
|
|
15
|
+
|
|
16
|
+
# Cooley-Tukey FFT (recursive)
|
|
17
|
+
if n & (n - 1) != 0:
|
|
18
|
+
# Simple padding to next power of 2 for this basic implementation
|
|
19
|
+
next_pow2 = 1 << (n - 1).bit_length()
|
|
20
|
+
padded_data = x._data + [0] * (next_pow2 - n)
|
|
21
|
+
x = ndarray(padded_data)
|
|
22
|
+
n = next_pow2
|
|
23
|
+
|
|
24
|
+
def _fft(data):
|
|
25
|
+
n = len(data)
|
|
26
|
+
if n <= 1:
|
|
27
|
+
return data
|
|
28
|
+
|
|
29
|
+
even = _fft(data[0::2])
|
|
30
|
+
odd = _fft(data[1::2])
|
|
31
|
+
|
|
32
|
+
T = [cmath.exp(-2j * math.pi * k / n) * odd[k] for k in range(n // 2)]
|
|
33
|
+
return [even[k] + T[k] for k in range(n // 2)] + \
|
|
34
|
+
[even[k] - T[k] for k in range(n // 2)]
|
|
35
|
+
|
|
36
|
+
res_data = _fft(x._data)
|
|
37
|
+
res = ndarray(0)
|
|
38
|
+
res._data = res_data
|
|
39
|
+
res._shape = (len(res_data),)
|
|
40
|
+
res.size = len(res_data)
|
|
41
|
+
return res
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from .core import ndarray
|
|
2
|
+
|
|
3
|
+
def transpose(a):
|
|
4
|
+
if not isinstance(a, ndarray):
|
|
5
|
+
a = ndarray(a)
|
|
6
|
+
|
|
7
|
+
if len(a.shape) != 2:
|
|
8
|
+
raise ValueError("Transpose only implemented for 2D arrays")
|
|
9
|
+
|
|
10
|
+
rows, cols = a.shape
|
|
11
|
+
new_data = [0] * a.size
|
|
12
|
+
for r in range(rows):
|
|
13
|
+
for c in range(cols):
|
|
14
|
+
new_data[c * rows + r] = a[r, c]
|
|
15
|
+
|
|
16
|
+
res = ndarray(0)
|
|
17
|
+
res._data = new_data
|
|
18
|
+
res._shape = (cols, rows)
|
|
19
|
+
res.size = a.size
|
|
20
|
+
return res
|
|
21
|
+
|
|
22
|
+
def dot(a, b):
|
|
23
|
+
if not isinstance(a, ndarray): a = ndarray(a)
|
|
24
|
+
if not isinstance(b, ndarray): b = ndarray(b)
|
|
25
|
+
|
|
26
|
+
# Simple vector dot product
|
|
27
|
+
if len(a.shape) == 1 and len(b.shape) == 1:
|
|
28
|
+
if a.shape[0] != b.shape[0]:
|
|
29
|
+
raise ValueError("Shapes not compatible for dot product")
|
|
30
|
+
return sum(x * y for x, y in zip(a._data, b._data))
|
|
31
|
+
|
|
32
|
+
# Matrix multiplication
|
|
33
|
+
if len(a.shape) == 2 and len(b.shape) == 2:
|
|
34
|
+
r1, c1 = a.shape
|
|
35
|
+
r2, c2 = b.shape
|
|
36
|
+
if c1 != r2:
|
|
37
|
+
raise ValueError("Shapes not compatible for matrix multiplication")
|
|
38
|
+
|
|
39
|
+
new_data = [0] * (r1 * c2)
|
|
40
|
+
for i in range(r1):
|
|
41
|
+
for j in range(c2):
|
|
42
|
+
s = 0
|
|
43
|
+
for k in range(c1):
|
|
44
|
+
s += a[i, k] * b[k, j]
|
|
45
|
+
new_data[i * c2 + j] = s
|
|
46
|
+
|
|
47
|
+
res = ndarray(0)
|
|
48
|
+
res._data = new_data
|
|
49
|
+
res._shape = (r1, c2)
|
|
50
|
+
res.size = r1 * c2
|
|
51
|
+
return res
|
|
52
|
+
|
|
53
|
+
raise NotImplementedError("Dot product only implemented for 1D/2D arrays")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import random as py_random
|
|
2
|
+
import math
|
|
3
|
+
from .core import ndarray
|
|
4
|
+
|
|
5
|
+
def uniform(low=0.0, high=1.0, size=None):
|
|
6
|
+
if size is None:
|
|
7
|
+
return py_random.uniform(low, high)
|
|
8
|
+
|
|
9
|
+
if isinstance(size, int):
|
|
10
|
+
size = (size,)
|
|
11
|
+
|
|
12
|
+
total_size = 1
|
|
13
|
+
for dim in size:
|
|
14
|
+
total_size *= dim
|
|
15
|
+
|
|
16
|
+
data = [py_random.uniform(low, high) for _ in range(total_size)]
|
|
17
|
+
res = ndarray(0)
|
|
18
|
+
res._data = data
|
|
19
|
+
res._shape = tuple(size)
|
|
20
|
+
res.size = total_size
|
|
21
|
+
return res
|
|
22
|
+
|
|
23
|
+
def normal(loc=0.0, scale=1.0, size=None):
|
|
24
|
+
if size is None:
|
|
25
|
+
return py_random.gauss(loc, scale)
|
|
26
|
+
|
|
27
|
+
if isinstance(size, int):
|
|
28
|
+
size = (size,)
|
|
29
|
+
|
|
30
|
+
total_size = 1
|
|
31
|
+
for dim in size:
|
|
32
|
+
total_size *= dim
|
|
33
|
+
|
|
34
|
+
data = [py_random.gauss(loc, scale) for _ in range(total_size)]
|
|
35
|
+
res = ndarray(0)
|
|
36
|
+
res._data = data
|
|
37
|
+
res._shape = tuple(size)
|
|
38
|
+
res.size = total_size
|
|
39
|
+
return res
|
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from heropy import ndarray
|
|
3
|
+
from heropy.linalg import dot, transpose
|
|
4
|
+
from heropy.fft import fft
|
|
5
|
+
from heropy.random import uniform, normal
|
|
6
|
+
|
|
7
|
+
class TestHeroPy(unittest.TestCase):
|
|
8
|
+
def test_core_init(self):
|
|
9
|
+
a = ndarray([[1, 2], [3, 4]])
|
|
10
|
+
self.assertEqual(a.shape, (2, 2))
|
|
11
|
+
self.assertEqual(a.size, 4)
|
|
12
|
+
|
|
13
|
+
def test_indexing(self):
|
|
14
|
+
a = ndarray([[1, 2], [3, 4]])
|
|
15
|
+
self.assertEqual(a[0, 1], 2)
|
|
16
|
+
a[1, 1] = 10
|
|
17
|
+
self.assertEqual(a[1, 1], 10)
|
|
18
|
+
|
|
19
|
+
def test_arithmetic(self):
|
|
20
|
+
a = ndarray([1, 2, 3])
|
|
21
|
+
b = ndarray([4, 5, 6])
|
|
22
|
+
self.assertEqual((a + b)._data, [5, 7, 9])
|
|
23
|
+
self.assertEqual((a * 2)._data, [2, 4, 6])
|
|
24
|
+
self.assertEqual((10 / a)._data[0], 10.0)
|
|
25
|
+
|
|
26
|
+
def test_linalg(self):
|
|
27
|
+
a = ndarray([[1, 2], [3, 4]])
|
|
28
|
+
at = transpose(a)
|
|
29
|
+
self.assertEqual(at[0, 1], 3)
|
|
30
|
+
|
|
31
|
+
b = ndarray([[5, 6], [7, 8]])
|
|
32
|
+
c = dot(a, b)
|
|
33
|
+
self.assertEqual(c[0, 0], 19)
|
|
34
|
+
|
|
35
|
+
def test_fft(self):
|
|
36
|
+
x = [1, 0, 0, 0]
|
|
37
|
+
res = fft(x)
|
|
38
|
+
self.assertAlmostEqual(res._data[0], 1.0)
|
|
39
|
+
self.assertAlmostEqual(res._data[3], 1.0)
|
|
40
|
+
|
|
41
|
+
def test_random(self):
|
|
42
|
+
u = uniform(0, 1, size=(10, 10))
|
|
43
|
+
self.assertEqual(u.shape, (10, 10))
|
|
44
|
+
|
|
45
|
+
def test_slicing(self):
|
|
46
|
+
a = ndarray([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
47
|
+
b = a[0:2, 1:3]
|
|
48
|
+
self.assertEqual(b.shape, (2, 2))
|
|
49
|
+
self.assertEqual(b._data, [2, 3, 5, 6])
|
|
50
|
+
|
|
51
|
+
def test_broadcasting_complex(self):
|
|
52
|
+
a = ndarray([[1, 2, 3], [4, 5, 6]])
|
|
53
|
+
b = ndarray([10, 20, 30])
|
|
54
|
+
c = a + b
|
|
55
|
+
self.assertEqual(c._data, [11, 22, 33, 14, 25, 36])
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
unittest.main()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heropy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A high-performance fundamental package for scientific computing with multi-dimensional arrays, linear algebra, and FFT.
|
|
5
|
+
Author-email: Death Legion Team <contact@deathlegion.team>
|
|
6
|
+
Project-URL: Homepage, https://github.com/deathlegion/heropy
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/deathlegion/heropy/issues
|
|
8
|
+
Keywords: scientific computing,multi-dimensional arrays,linear algebra,FFT,matrix,numerical computing,data science,machine learning
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# HeroPy: High-Performance Scientific Computing in Python
|
|
20
|
+
|
|
21
|
+
HeroPy is the fundamental package for scientific computing with Python, meticulously crafted by the **Death Legion Team**. It provides a powerful N-dimensional array object, sophisticated mathematical functions, and the core data structures necessary for modern data science and machine learning.
|
|
22
|
+
|
|
23
|
+
[](https://badge.fury.io/py/heropy)
|
|
24
|
+
[](https://opensource.org/licenses/MIT)
|
|
25
|
+
|
|
26
|
+
## Why HeroPy?
|
|
27
|
+
|
|
28
|
+
In the evolving landscape of numerical computing, HeroPy stands as a robust foundation for handling large, multi-dimensional arrays and matrices. Designed for performance and ease of use, HeroPy enables complex mathematical operations on entire blocks of data without the need for slow Python loops.
|
|
29
|
+
|
|
30
|
+
## Core Features
|
|
31
|
+
|
|
32
|
+
- **N-Dimensional Array (`ndarray`)**: A versatile, multi-dimensional array object with support for advanced indexing, slicing, and NumPy-style broadcasting.
|
|
33
|
+
- **Linear Algebra (`linalg`)**: High-level mathematical functions for matrix multiplication (`dot`), transposition, and vector operations.
|
|
34
|
+
- **Fourier Transforms (`fft`)**: Efficient Fast Fourier Transform (FFT) capabilities for signal processing and spectral analysis.
|
|
35
|
+
- **Random Number Generation (`random`)**: Sophisticated random number generation with support for various distributions like Uniform and Normal (Gaussian).
|
|
36
|
+
- **Extensible Architecture**: Built to be the bedrock of the Python data science ecosystem, compatible with machine learning and data analysis workflows.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Clone the repository
|
|
42
|
+
git clone <repo-url>
|
|
43
|
+
cd heropy
|
|
44
|
+
export PYTHONPATH=$PYTHONPATH:.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import heropy as hp
|
|
51
|
+
from heropy.linalg import dot
|
|
52
|
+
|
|
53
|
+
# Create arrays
|
|
54
|
+
a = hp.ndarray([[1, 2], [3, 4]])
|
|
55
|
+
b = hp.ndarray([10, 20])
|
|
56
|
+
|
|
57
|
+
# Arithmetic with broadcasting
|
|
58
|
+
c = a + b
|
|
59
|
+
|
|
60
|
+
# Matrix multiplication
|
|
61
|
+
d = dot(a, a)
|
|
62
|
+
|
|
63
|
+
# FFT
|
|
64
|
+
from heropy.fft import fft
|
|
65
|
+
freq = fft([1, 0, 1, 0])
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Performance Note
|
|
69
|
+
|
|
70
|
+
HeroPy is currently implemented in pure Python for maximum portability and clarity. While it provides the core data structures and operations, performance for very large datasets may be limited compared to C-accelerated libraries.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
heropy/__init__.py
|
|
4
|
+
heropy/core.py
|
|
5
|
+
heropy/fft.py
|
|
6
|
+
heropy/linalg.py
|
|
7
|
+
heropy/random.py
|
|
8
|
+
heropy.egg-info/PKG-INFO
|
|
9
|
+
heropy.egg-info/SOURCES.txt
|
|
10
|
+
heropy.egg-info/dependency_links.txt
|
|
11
|
+
heropy.egg-info/top_level.txt
|
|
12
|
+
heropy/tests/__init__.py
|
|
13
|
+
heropy/tests/test_all.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
heropy
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "heropy"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Death Legion Team", email="contact@deathlegion.team" },
|
|
10
|
+
]
|
|
11
|
+
description = "A high-performance fundamental package for scientific computing with multi-dimensional arrays, linear algebra, and FFT."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Scientific/Engineering",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
20
|
+
"Intended Audience :: Science/Research",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
]
|
|
23
|
+
keywords = ["scientific computing", "multi-dimensional arrays", "linear algebra", "FFT", "matrix", "numerical computing", "data science", "machine learning"]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
"Homepage" = "https://github.com/deathlegion/heropy"
|
|
27
|
+
"Bug Tracker" = "https://github.com/deathlegion/heropy/issues"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
where = ["."]
|
|
31
|
+
include = ["heropy*"]
|
heropy-0.1.0/setup.cfg
ADDED