numox 1.0.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.
- numox-1.0.0/PKG-INFO +57 -0
- numox-1.0.0/README.md +44 -0
- numox-1.0.0/matrix.c +371 -0
- numox-1.0.0/numox.c +1172 -0
- numox-1.0.0/numox.egg-info/PKG-INFO +57 -0
- numox-1.0.0/numox.egg-info/SOURCES.txt +9 -0
- numox-1.0.0/numox.egg-info/dependency_links.txt +1 -0
- numox-1.0.0/numox.egg-info/top_level.txt +1 -0
- numox-1.0.0/pyproject.toml +3 -0
- numox-1.0.0/setup.cfg +4 -0
- numox-1.0.0/setup.py +38 -0
numox-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: numox
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A high-performance C Extension for matrix math
|
|
5
|
+
Author: oxoxox-oxox
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: description
|
|
10
|
+
Dynamic: description-content-type
|
|
11
|
+
Dynamic: requires-python
|
|
12
|
+
Dynamic: summary
|
|
13
|
+
|
|
14
|
+
# numox
|
|
15
|
+
|
|
16
|
+
A high-performance Python C-extension for matrix mathematics, accelerated with OpenMP, AVX, and FMA instructions.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
### From Source (Requires C compiler)
|
|
21
|
+
|
|
22
|
+
You can install `numox` directly from this GitHub repository:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Note: Ensure you have a C compiler (GCC/Clang) with OpenMP support installed.
|
|
26
|
+
pip install git https://github.com/YourUsername/numox.git
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Docker Development Environment
|
|
30
|
+
|
|
31
|
+
If you want a clean, "painless" environment to compile and test the C-extension without configuring your local machine, use the provided Ubuntu 22.04 Dockerfile:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 1. Build the docker image
|
|
35
|
+
docker build -t numox-env .
|
|
36
|
+
|
|
37
|
+
# 2. Run the container, mounting your current code directory
|
|
38
|
+
docker run -it --rm -v "${PWD}:/workspace" numox-env bash
|
|
39
|
+
|
|
40
|
+
# 3. Inside the container, install the library or run tests
|
|
41
|
+
pip install .
|
|
42
|
+
make test
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import numox as nc
|
|
49
|
+
|
|
50
|
+
# Create a 3x3 matrix initialized with random values between 0.0 and 1.0
|
|
51
|
+
mat1 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
|
|
52
|
+
mat2 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
|
|
53
|
+
|
|
54
|
+
# Perform fast matrix operations
|
|
55
|
+
result = mat1 + mat2
|
|
56
|
+
print(result.to_list())
|
|
57
|
+
```
|
numox-1.0.0/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# numox
|
|
2
|
+
|
|
3
|
+
A high-performance Python C-extension for matrix mathematics, accelerated with OpenMP, AVX, and FMA instructions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### From Source (Requires C compiler)
|
|
8
|
+
|
|
9
|
+
You can install `numox` directly from this GitHub repository:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Note: Ensure you have a C compiler (GCC/Clang) with OpenMP support installed.
|
|
13
|
+
pip install git https://github.com/YourUsername/numox.git
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Docker Development Environment
|
|
17
|
+
|
|
18
|
+
If you want a clean, "painless" environment to compile and test the C-extension without configuring your local machine, use the provided Ubuntu 22.04 Dockerfile:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# 1. Build the docker image
|
|
22
|
+
docker build -t numox-env .
|
|
23
|
+
|
|
24
|
+
# 2. Run the container, mounting your current code directory
|
|
25
|
+
docker run -it --rm -v "${PWD}:/workspace" numox-env bash
|
|
26
|
+
|
|
27
|
+
# 3. Inside the container, install the library or run tests
|
|
28
|
+
pip install .
|
|
29
|
+
make test
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import numox as nc
|
|
36
|
+
|
|
37
|
+
# Create a 3x3 matrix initialized with random values between 0.0 and 1.0
|
|
38
|
+
mat1 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
|
|
39
|
+
mat2 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
|
|
40
|
+
|
|
41
|
+
# Perform fast matrix operations
|
|
42
|
+
result = mat1 + mat2
|
|
43
|
+
print(result.to_list())
|
|
44
|
+
```
|
numox-1.0.0/matrix.c
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#include "matrix.h"
|
|
2
|
+
#include <stddef.h>
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include <omp.h>
|
|
6
|
+
|
|
7
|
+
// Include SSE intrinsics
|
|
8
|
+
#if defined(_MSC_VER)
|
|
9
|
+
#include <intrin.h>
|
|
10
|
+
#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
|
|
11
|
+
#include <immintrin.h>
|
|
12
|
+
#include <x86intrin.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
/* Below are some intel intrinsics that might be useful
|
|
16
|
+
* void _mm256_storeu_pd (double * mem_addr, __m256d a)
|
|
17
|
+
* __m256d _mm256_set1_pd (double a)
|
|
18
|
+
* __m256d _mm256_set_pd (double e3, double e2, double e1, double e0)
|
|
19
|
+
* __m256d _mm256_loadu_pd (double const * mem_addr)
|
|
20
|
+
* __m256d _mm256_add_pd (__m256d a, __m256d b)
|
|
21
|
+
* __m256d _mm256_sub_pd (__m256d a, __m256d b)
|
|
22
|
+
* __m256d _mm256_fmadd_pd (__m256d a, __m256d b, __m256d c)
|
|
23
|
+
* __m256d _mm256_mul_pd (__m256d a, __m256d b)
|
|
24
|
+
* __m256d _mm256_cmp_pd (__m256d a, __m256d b, const int imm8)
|
|
25
|
+
* __m256d _mm256_and_pd (__m256d a, __m256d b)
|
|
26
|
+
* __m256d _mm256_max_pd (__m256d a, __m256d b)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Generates a random double between `low` and `high`.
|
|
31
|
+
*/
|
|
32
|
+
double rand_double(double low, double high)
|
|
33
|
+
{
|
|
34
|
+
double range = (high - low);
|
|
35
|
+
double div = RAND_MAX / range;
|
|
36
|
+
return low + (rand() / div);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* Generates a random matrix with `seed`.
|
|
41
|
+
*/
|
|
42
|
+
void rand_matrix(matrix *result, unsigned int seed, double low, double high)
|
|
43
|
+
{
|
|
44
|
+
srand(seed);
|
|
45
|
+
for (int i = 0; i < result->rows; i++)
|
|
46
|
+
{
|
|
47
|
+
for (int j = 0; j < result->cols; j++)
|
|
48
|
+
{
|
|
49
|
+
set(result, i, j, rand_double(low, high));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
*Allocate space for matrix, init all the element in the matrix to 0
|
|
56
|
+
*/
|
|
57
|
+
int allocate_matrix(matrix **mat, int rows, int cols)
|
|
58
|
+
{
|
|
59
|
+
if (mat == NULL || rows <= 0 || cols <= 0)
|
|
60
|
+
{
|
|
61
|
+
return -1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
matrix *m = malloc(sizeof(matrix));
|
|
65
|
+
if (m == NULL)
|
|
66
|
+
{
|
|
67
|
+
free(m);
|
|
68
|
+
return -1;
|
|
69
|
+
}
|
|
70
|
+
m->rows = rows;
|
|
71
|
+
m->cols = cols;
|
|
72
|
+
m->is_1d = rows == 1 || cols == 1;
|
|
73
|
+
m->ref_cnt = 1;
|
|
74
|
+
m->data = malloc(rows * sizeof(double *));
|
|
75
|
+
m->parent = NULL;
|
|
76
|
+
|
|
77
|
+
if (m->data == NULL)
|
|
78
|
+
{
|
|
79
|
+
free(m->data);
|
|
80
|
+
free(m);
|
|
81
|
+
return -1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (int i = 0; i < rows; i++)
|
|
85
|
+
{
|
|
86
|
+
m->data[i] = malloc(cols * sizeof(double));
|
|
87
|
+
if (m->data[i] == NULL)
|
|
88
|
+
{
|
|
89
|
+
for (int j = 0; j <= i; j++)
|
|
90
|
+
{
|
|
91
|
+
free(m->data[j]);
|
|
92
|
+
}
|
|
93
|
+
free(m->data);
|
|
94
|
+
free(m);
|
|
95
|
+
return -1;
|
|
96
|
+
}
|
|
97
|
+
for (int j = 0; j < cols; j++)
|
|
98
|
+
{
|
|
99
|
+
m->data[i][j] = 0.0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
*mat = m;
|
|
104
|
+
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
*allocate space for ref of one existing matrix
|
|
110
|
+
*/
|
|
111
|
+
int allocate_matrix_ref(matrix **mat, matrix *from, int row_offset, int col_offset,
|
|
112
|
+
int rows, int cols)
|
|
113
|
+
{
|
|
114
|
+
matrix *m = malloc(sizeof(matrix));
|
|
115
|
+
if (m == NULL || rows < 1 || cols < 1)
|
|
116
|
+
{
|
|
117
|
+
free(m);
|
|
118
|
+
return -1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
m->rows = rows;
|
|
122
|
+
m->cols = cols;
|
|
123
|
+
m->is_1d = rows == 1 || cols == 1;
|
|
124
|
+
m->ref_cnt = 0;
|
|
125
|
+
m->parent = from;
|
|
126
|
+
|
|
127
|
+
m->data = malloc(rows * sizeof(double *));
|
|
128
|
+
if (m->data == NULL)
|
|
129
|
+
{
|
|
130
|
+
free(m->data);
|
|
131
|
+
free(m);
|
|
132
|
+
return -1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (int i = 0; i < rows; i++)
|
|
136
|
+
{
|
|
137
|
+
m->data[i] = from->data[row_offset + i] + col_offset;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
from->ref_cnt += 1;
|
|
141
|
+
|
|
142
|
+
*mat = m;
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
*deallocate the matrix, also allocate the father of the matrix if it exist
|
|
148
|
+
*/
|
|
149
|
+
void deallocate_matrix(matrix *mat)
|
|
150
|
+
{
|
|
151
|
+
if (mat == NULL)
|
|
152
|
+
{
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
mat->ref_cnt -= 1;
|
|
157
|
+
|
|
158
|
+
if (mat->ref_cnt > 0)
|
|
159
|
+
{
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (mat->parent == NULL)
|
|
164
|
+
{
|
|
165
|
+
for (int i = 0; i < mat->rows; i++)
|
|
166
|
+
{
|
|
167
|
+
free(mat->data[i]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else
|
|
171
|
+
{
|
|
172
|
+
deallocate_matrix(mat->parent);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
free(mat->data);
|
|
176
|
+
free(mat);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Return the double value of the matrix at the given row and column.
|
|
181
|
+
*/
|
|
182
|
+
double get(matrix *mat, int row, int col)
|
|
183
|
+
{
|
|
184
|
+
return mat->data[row][col];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* Set the value at the given row and column to val.
|
|
189
|
+
*/
|
|
190
|
+
void set(matrix *mat, int row, int col, double val)
|
|
191
|
+
{
|
|
192
|
+
mat->data[row][col] = val;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* Set all entries in mat to val
|
|
197
|
+
*/
|
|
198
|
+
void fill_matrix(matrix *mat, double val)
|
|
199
|
+
{
|
|
200
|
+
for (int i = 0; i < mat->rows; i++)
|
|
201
|
+
{
|
|
202
|
+
for (int j = 0; j < mat->cols; j++)
|
|
203
|
+
{
|
|
204
|
+
mat->data[i][j] = val;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/*
|
|
210
|
+
* Store the result of adding mat1 and mat2 to `result`.
|
|
211
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
212
|
+
*/
|
|
213
|
+
int add_matrix(matrix *result, matrix *mat1, matrix *mat2)
|
|
214
|
+
{
|
|
215
|
+
if (mat1->rows != mat2->rows || mat1->cols != mat2->cols)
|
|
216
|
+
{
|
|
217
|
+
return -1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
int row = mat1->rows;
|
|
221
|
+
int col = mat2->cols;
|
|
222
|
+
|
|
223
|
+
for (int i = 0; i < row; i++)
|
|
224
|
+
{
|
|
225
|
+
for (int j = 0; j < col; j++)
|
|
226
|
+
{
|
|
227
|
+
result->data[i][j] = mat1->data[i][j] + mat2->data[i][j];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
* Store the result of subtracting mat2 from mat1 to `result`.
|
|
236
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
237
|
+
*/
|
|
238
|
+
int sub_matrix(matrix *result, matrix *mat1, matrix *mat2)
|
|
239
|
+
{
|
|
240
|
+
if (mat1->rows != mat2->rows || mat1->cols != mat2->cols)
|
|
241
|
+
{
|
|
242
|
+
return -1;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
int row = mat1->rows;
|
|
246
|
+
int col = mat2->cols;
|
|
247
|
+
|
|
248
|
+
for (int i = 0; i < row; i++)
|
|
249
|
+
{
|
|
250
|
+
for (int j = 0; j < col; j++)
|
|
251
|
+
{
|
|
252
|
+
result->data[i][j] = mat1->data[i][j] - mat2->data[i][j];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* Store the result of multiplying mat1 and mat2 to `result`.
|
|
261
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
262
|
+
*/
|
|
263
|
+
int mul_matrix(matrix *result, matrix *mat1, matrix *mat2)
|
|
264
|
+
{
|
|
265
|
+
int row1 = mat1->rows;
|
|
266
|
+
int row2 = mat2->rows;
|
|
267
|
+
int col1 = mat1->cols;
|
|
268
|
+
int col2 = mat2->cols;
|
|
269
|
+
|
|
270
|
+
if (col1 != row2)
|
|
271
|
+
{
|
|
272
|
+
return -1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
for (int i = 0; i < row1; i++)
|
|
276
|
+
{
|
|
277
|
+
for (int j = 0; j < col2; j++)
|
|
278
|
+
{
|
|
279
|
+
double sum = 0.0;
|
|
280
|
+
for (int k = 0; k < col1; k++)
|
|
281
|
+
{
|
|
282
|
+
sum += mat1->data[i][k] * mat2->data[k][j];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
result->data[i][j] = sum;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* Store the result of raising mat to the (pow)th power to `result`.
|
|
294
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
295
|
+
*/
|
|
296
|
+
int pow_matrix(matrix *result, matrix *mat, int pow)
|
|
297
|
+
{
|
|
298
|
+
matrix *template;
|
|
299
|
+
allocate_matrix(&template, mat->rows, mat->cols);
|
|
300
|
+
|
|
301
|
+
for (int r = 0; r < mat->rows; r++)
|
|
302
|
+
{
|
|
303
|
+
for (int c = 0; c < mat->cols; c++)
|
|
304
|
+
{
|
|
305
|
+
result->data[r][c] = mat->data[r][c];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 循环 pow - 1 次
|
|
310
|
+
for (int step = 0; step < pow - 1; step++)
|
|
311
|
+
{
|
|
312
|
+
// 拿当前的 result 去乘 mat,算好的结果丢进安全的 template 里
|
|
313
|
+
mul_matrix(template, result, mat);
|
|
314
|
+
|
|
315
|
+
// 把最新结果从 template 拷回 result
|
|
316
|
+
for (int r = 0; r < mat->rows; r++)
|
|
317
|
+
{
|
|
318
|
+
for (int c = 0; c < mat->cols; c++)
|
|
319
|
+
{
|
|
320
|
+
result->data[r][c] = template->data[r][c];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
deallocate_matrix(template);
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* Store the result of element-wise negating mat's entries to `result`.
|
|
331
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
332
|
+
*/
|
|
333
|
+
int neg_matrix(matrix *result, matrix *mat)
|
|
334
|
+
{
|
|
335
|
+
int row = mat->rows;
|
|
336
|
+
int col = mat->cols;
|
|
337
|
+
|
|
338
|
+
for (int i = 0; i < row; i++)
|
|
339
|
+
{
|
|
340
|
+
for (int j = 0; j < col; j++)
|
|
341
|
+
{
|
|
342
|
+
double num = mat->data[i][j];
|
|
343
|
+
result->data[i][j] = -1 * num;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/*
|
|
350
|
+
* Store the result of taking the absolute value element-wise to `result`.
|
|
351
|
+
* Return 0 upon success and a -1 value upon failure.
|
|
352
|
+
*/
|
|
353
|
+
int abs_matrix(matrix *result, matrix *mat)
|
|
354
|
+
{
|
|
355
|
+
int row = mat->rows;
|
|
356
|
+
int col = mat->cols;
|
|
357
|
+
|
|
358
|
+
for (int i = 0; i < row; i++)
|
|
359
|
+
{
|
|
360
|
+
for (int j = 0; j < col; j++)
|
|
361
|
+
{
|
|
362
|
+
double num = mat->data[i][j];
|
|
363
|
+
if (num <= 0)
|
|
364
|
+
{
|
|
365
|
+
num = -num;
|
|
366
|
+
}
|
|
367
|
+
result->data[i][j] = num;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return 0;
|
|
371
|
+
}
|